本文摘抄自:https://blog.csdn.net/pashanhu6402/article/details/96428887

https://blog.csdn.net/liuyueyue0921/article/details/47830517

https://blog.csdn.net/weixin_38534337/article/details/84316251

1、什么是TCP/IP、UDP?

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

TCP/IP协议族包括运输层、网络层、链路层。如下图

2、Socket在哪里呢?

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,如下图。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

3、Socket通信流程

socket通信流程如下图

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

4、网络中进程之间如何通信?

网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。网络中的进程是通过socket来通信的。

5、什么是Socket

Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。

socket在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的,撰写者为Stephen Carr、Steve Crocker和Vint Cerf。根据美国计算机历史博物馆的记载,Croker写道:“命名空间的元素都可称为套接字接口。一个套接字接口构成一个连接的一端,而一个连接可完全由一对套接字接口规定。”计算机历史博物馆补充道:“这比BSD的套接字接口定义早了大约12年。”

6、socket的基本操作

既然socket是“open—write/read—close”模式的一种实现,那么socket就提供了这些操作对应的函数接口。下面以TCP为例,介绍几个基本的socket接口函数。

6.1、socket()函数

int socket(int domain, int type, int protocol);

socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而**socket()**用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

正如可以给fopen的传入不同参数值,以打开不同的文件。创建socket的时候,也可以指定不同的参数创建不同的socket描述符,socket函数的三个参数分别为:

  • domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合,它是面向网络的、AF_UNIX决定了要用一个绝对路径名作为地址,它是基于文件的。
  • type:指定socket类型。常用的socket类型有,SOCK_STREAM(面向连接可靠方式,比如TCP)、SOCK_DGRAM(非面向连接的非可靠方式,比如UDP)、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。
  • protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议。

注意:并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。

socket返回的值是一个文件描述符,SOCKET类型本身也是定义为int的,既然是文件描述符,那么在系统中都当作是文件来对待的,0,1,2分别表示标准输入、标准输出、标准错误。所以其他打开的文件描述符都会大于2, 错误时就返回 -1. 这里INVALID_SOCKET 也被定义为 -1 。

当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。

6.2、setsockopt

setsockopt()函数,用于任意类型、任意状态套接口的设置选项值。

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

  • sockfd:标识一个套接口的描述字。

  • level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。

  • optname:需设置的选项。

  • optval:指针,指向存放选项待设置的新值的缓冲区。

  • optlen:optval缓冲区长度。

    int nEnabled = 1;
    ::setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
    reinterpret_cast<const char*>(&nEnabled), sizeof(nEnabled));

SO_REUSEADDR是一个可以被设置的选项,一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用。server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。TCP,先调用close()的一方会进入TIME_WAIT状态

SO_REUSEADDR可以用在以下四种情况下: (摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可
以测试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。

6.3、bind()函数

bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数的三个参数分别为:

  • sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。

  • addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:

    struct sockaddr_in {sa_family_t    sin_family; in_port_t      sin_port;   struct in_addr sin_addr;
    };struct in_addr {uint32_t       s_addr;
    };
    

    ipv6对应的是:

    struct sockaddr_in6 { sa_family_t     sin6_family;    in_port_t       sin6_port;      uint32_t        sin6_flowinfo;  struct in6_addr sin6_addr;      uint32_t        sin6_scope_id;
    };struct in6_addr { unsigned char   s6_addr[16];
    };
    

    Unix域对应的是:

    #define UNIX_PATH_MAX    108struct sockaddr_un { sa_family_t sun_family;                char        sun_path[UNIX_PATH_MAX];
    };
    
  • addrlen:对应的是地址的长度。

通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。

6.4、listen()、connect()函数

如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

6.5、accept()函数

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

注意:accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。

6.6、read()、write()等函数

万事具备只欠东风,至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,即实现了网咯中不同进程之间的通信!网络I/O操作有下面几组:

  • read()/write()
  • recv()/send()
  • readv()/writev()
  • recvmsg()/sendmsg()
  • recvfrom()/sendto()

我推荐使用recvmsg()/sendmsg()函数,这两个函数是最通用的I/O函数,实际上可以把上面的其它函数都替换成这两个函数。它们的声明如下:

 #include ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);#include #include ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了,小于0表示出现了错误。如果错误为EINTR说明读是由中断引起的,如果是ECONNREST表示网络连接出了问题。

write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节 数。失败时返回-1,并设置errno变量。在网络程序中,当我们向套接字文件描述符写时有俩种可能。1)write的返回值大于0,表示写了部分或者是 全部的数据。2)返回的值小于0,此时出现了错误。我们要根据错误类型来处理。如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示 网络连接出现了问题(对方已经关闭了连接)。

其它的我就不一一介绍这几对I/O函数了,具体参见man文档或者baidu、Google,下面的例子中将使用到send/recv。

6.7、close()函数

在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。

#include
int close(int fd);

close一个TCP socket的缺省行为时把该socket标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。

注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

6.8、网络字节序、主机字节序、点分十进制串

6.8.1 、主机字节序

主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下:

a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

6.8.2、网络字节序

4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。所以,在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。

6.8.3、点分十进制串

就是我们通常用的ip地址格式: XXX.XXX.XXX.XXX

6.8.4、转换函数

6.8.4.1、htonl,inet_addr,ip地址主机字节序转换成网络字节序

假设ip地址为127 . 0 . 0 . 1 ,主机字节序转换成网络字节序的步骤:

  • 第一步 127 . 0 . 0 . 1 把IP地址每一部分转换为8位的二进制数。
  • 第二步 01111111 00000000 00000000 00000001 = 2130706433 (主机字节序)
    然后把上面的四部分二进制数从右往左按部分重新排列,那就变为:
  • 第三步 00000001 00000000 00000000 01111111 = 16777343 (网络字节序)

htonl是上述第二步到第三步的转换

inet_addr是上述第一步到第三步的转换

转换函数:htonl(),意思是:host to network,l是long的意思,头文件是:#include <arpa/inet.h>

下面两行代码实现的效果是一样的

addr.sin_addr.s_addr=htonl(2130706433);这句还可以写为:
addr.sin_addr.s_addr=inet_addr(“127.0.0.1”); 结果是完全一样的。
addr.sin_addr.s_addr = htonl(INADDR_ANY);

INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。也就是表示本机的所有IP,因为有些机子不止一块网卡,多网卡的情况下,这个就表示所有网卡ip地址的意思。客户端connect时,不能使用INADDR_ANY选项。必须指明要连接哪个服务器IP。

6.8.4.2、htons,端口主机字节序转换成网络字节序

端口号其实就已经是主机字节序了,以6000端口为例,首先要把端口号写为16位的二进制数,分前8位和后8位。

  • 第一步 00010111 01110000 = 6000 (主机字节序)
    然后把主机字节序的前八位与后八位调换位置组成新的16位二进制数,这新的16位二进制数就是网络字节序的二进制表示了。
  • 第二步 01110000 00010111 = 28695 (网络字节序)

下面两行代码实现的效果是一样的

addrSrv.sin_port=htons(6000);还可以写为
addrSrv.sin_port=28695;结果是一样的,
6.8.4.3、 ntohl,ntohs,网络字节序转换成端口主机字节序

与上面两个过程相反:

uint32_t  ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
6.8.4.4 、inet_pton点分十进制串转换成网络字节序

如同6.8.4.1中第一步到第三步,可用inet_addr,也可用inet_pton

int inet_pton(int af, const char *src, void *dst);

下面三行代码效果一样

addr.sin_addr.s_addr=htonl(2130706433);
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
inet_pton(AF_INET, "127.0.0.1",  (void *)&addr.sin_addr.s_addr);
6.8.4.5 、inet_ntop网络字节序转换成点分十进制串

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和inet_pton相同,只是多了一个参数socklen_t cnt,他是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC

struct sockaddr_in addr = {0};
socklen_t nSize = sizeof(addr);
NativeSocket client = ::accept(socket_, reinterpret_cast<sockaddr*>(&addr), &nSize);
if (client == INVALID_SOCKET) { return nullptr; }
char sTmp[64]; sTmp[0] = '\0'; sTmp[63] = '\0';
const char* sPeerAddress = inet_ntop(AF_INET, &addr.sin_addr, sTmp, 63);

7、socket中TCP的三次握手建立连接详解

我们知道tcp建立连接要进行“三次握手”,即交换三个分组。大致流程如下:

  • 客户端向服务器发送一个SYN J
  • 服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1
  • 客户端再想服务器发一个确认ACK K+1

只有就完了三次握手,但是这个三次握手发生在socket的那几个函数中呢?请看下图

从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

总结:客户端的connect在三次握手的第二个次返回,而服务器端的accept在三次握手的第三次返回。

8、socket中TCP的四次握手释放连接详解

上面介绍了socket中TCP的三次握手建立过程,及其涉及的socket函数。现在我们介绍socket中的四次握手释放连接的过程,请看下图:

图示过程如下:

  • 某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
  • 另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
  • 一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
  • 接收到这个FIN的源发送端TCP对它进行确认。

这样每个方向上都有一个FIN和ACK。

9、实现实例

2021/03/24编写

服务器端代码如下:

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <cassert>
#include <unistd.h>
#include <fcntl.h>typedef int NativeSocket;#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif#ifndef INVALID_SOCKET
#define INVALID_SOCKET  static_cast<NativeSocket>(-1)
#endifint main(int argc, char** argv)
{//创建套节字int socket = ::socket(AF_INET, SOCK_STREAM, 0); if (socket == INVALID_SOCKET){std::cout << "Failed to create server socket." << std::endl;return -1;}//设置SO_REUSEADDR选项,使得端口释放后立即就可以被再次使用int nEnabled = 1;::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR,reinterpret_cast<const char*>(&nEnabled), sizeof(nEnabled));//绑定这个套节字到一个本地地址struct sockaddr_in addr = {0};addr.sin_family = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port = htons(9090);if (::bind(socket, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) {printf("bind failed\n");return -1;}//进入监听模式if (::listen(socket, 5) == SOCKET_ERROR) {printf("listen failed\n");return -1;}int accepted = 0;int client_socket = -1;while(accepted == 0) {//接受客户的连接请求struct sockaddr_in addr = {0};socklen_t nSize = sizeof(addr);client_socket = ::accept(socket, reinterpret_cast<sockaddr*>(&addr), &nSize);if (client_socket == INVALID_SOCKET) {return -1;}char sTmp[64]; sTmp[0] = '\0'; sTmp[63] = '\0';const char* sPeerAddress = inet_ntop(AF_INET, &addr.sin_addr, sTmp, 63);std::cout << "client ip = " << sPeerAddress << std::endl;accepted ++;}char szText[256];while(true) {std::cin.getline(szText, 256);szText[255] = '\0';// 向客户端发送数据::send(client_socket, szText, strlen(szText), 0);// 从客户端接收数据 char buff[256] ;int nRecv = ::recv(client_socket, buff, 256, 0); if (nRecv > 0){buff[nRecv] = '\0';printf(" 接收到数据:%s\n", buff);}}// 关闭同客户端的连接::close(client_socket);// 关闭监听套节字::close(socket);return 0;
}

客户端代码:

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdio.h>
#include <cassert>
#include <unistd.h>
#include <fcntl.h>typedef int NativeSocket;#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif#ifndef INVALID_SOCKET
#define INVALID_SOCKET  static_cast<NativeSocket>(-1)
#endifint main(int argc, char** argv)
{//创建套节字int socket = ::socket(AF_INET, SOCK_STREAM, 0);if (socket == INVALID_SOCKET){std::cout << "Failed to create client socket." << std::endl;return -1;}//连接serverstruct sockaddr_in addr = {0};addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr("172.16.82.52");addr.sin_port = htons(9090);if(::connect(socket, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) {printf(" Failed connect() \n");return 0; }char buff[256];char szText[256];while(true){//从服务器端接收数据int nRecv = ::recv(socket, buff, 256, 0);if(nRecv > 0){buff[nRecv] = '\0';printf("接收到数据:%s\n", buff);}// 向服务器端发送数据std::cin.getline(szText, 256);szText[255] = '\0';::send(socket, szText, strlen(szText), 0) ;}// 关闭套节字::close(socket);return 0;
}

socket原理及实现相关推荐

  1. c语言socket原理,Socket底层原理

    Socket两个基本概念:客户方和服务方.当两个应用之间需要采用SOCKET通信时,首先需要在两个应用之间(可能位于同一台机器,也可能位于不同的机器)建立SOCKET连接,发起呼叫连接请求的一方为客户 ...

  2. linux socket原理,socket 的工作原理

    首先谈一下Socket 机制本身,socket为各种协议提供了统一接口的一种ipc机制.在linux中,它由几个部分组成.为了讨论,先讨论几个数据结构,如下所示: struct net_proto_f ...

  3. TCP三次握手、四次挥手、socket,tcp,http三者之间的区别和原理

    接着上一篇文章叙述: TCP/IP连接(在互联网的通信中,永远是客户端主动连接到服务端): 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接.TCP协 ...

  4. socket通信原理简介

    Socket原理,大致分为以下几个步骤. 服务器端的步骤如下: (1)首先,在实用Socket之前,要首先初始化Socket,就是实用AfxSocketInit()函数. (2)在初始化完成以后,就可 ...

  5. socket的原理和实验

    1.socket原理 根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认. (1)服务器监听:是服务器端套接字并不定位具体的客户端套接 ...

  6. 对Socket CAN的理解(1)——【CAN总线原理】

    转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 由于Socket CAN涉及到CAN总线协议.套接字.Linux网络设备驱动等.因此,为了能够全面地了解Socket ...

  7. Socket接口及原理

    Socket原理:服务端有一个进程(或者多个进程)在指定端口等待客户来连接,服务程序等待客户的连接信息,一旦连接上之后,就可以按设计的数据交换方法和格式进行数据传输.客户端在需要的时刻发出向服务器端的 ...

  8. Http和Socket连接区别(ZT)

    1.TCP连接 要想明白Socket连接,先要明白TCP连接.手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接.TCP协议可以对上层网络提供接口,使上 ...

  9. iOS端Socket连接、发送数据(一)

    一.Socket的应用 IM即时通讯是通过Socket的方式实现长连接,可运用于 (1)直播聊天室.礼物 (2)微信.QQ等即时聊天 (3)游戏对话.技能等 二.SOCKET原理 套接字(socket ...

  10. TCP/IP、SOCKET、HTTP之间的联系与区别

    主要内容: 1.网络的七层协议 2.TCP/IP.SOCKET.HTTP简介 3.TCP连接.HTTP连接.Socket连接的区别 一.网络的七层协议 网络七层由下往上分别为物理层.数据链路层.网络层 ...

最新文章

  1. 借一个同事的经历,谈一谈程序员的成长
  2. webuploader自己造的坑
  3. Linux而不必进入password登陆自己主动sshserver方法
  4. 【树链剖分】Milk Visits G(luogu 5838)
  5. jq实现前端文件上传
  6. HTTP状态码表格汇总
  7. Windows文件服务器会话清理,在 Windows Server 上使用磁盘清理
  8. UML 10 种常见的域建模错误
  9. 当我们谈论 996 的时候我们在谈论什么?
  10. poj2386(简单的dfs/bfs)
  11. JavaScript入门思维导图
  12. 为什么公司宁愿花15k去重招一个应届生,也不愿意加薪5k留住老程序员?
  13. 硬盘坏道数据如何恢复?如何知道硬盘是否坏道?
  14. sklearn.neighbors.KNeighborsClassifier()函数解析(最清晰的解释)
  15. 阿里程序员试用期被淘汰,原因竟是?
  16. 全球博士Talk NeurIPS 2022 预讲会完美收官,27位博士生共话机器学习前沿研究
  17. 浙江环宇集团“营改增”项目启动会成功举办
  18. Redis key键命令
  19. 桌面计算机和笔记本被称为,网络上常见的PC是什么意思?深度解读计算机发展史...
  20. 绝妙四道题(C语言)

热门文章

  1. 计算机打印共享打印机,教您电脑打印机共享怎么设置
  2. (转)简体繁体转换代码(Big5-GB | GBK简体-GBK繁体)
  3. 利用Scrapy爬取豆瓣电影
  4. 获取Windows聚焦的图片
  5. 利用NetToPLCsim将西门子PLCSIM变成一个真实PLC,实现与录波软件、HMI软件等的通讯
  6. 广外男生病毒代码剖析
  7. matlab贝塞尔函数零点,第一类贝塞尔函数零点求解matlab程序
  8. Linux有道词典依赖问题
  9. 医疗器材行业如何利用三类医疗器械进销存软件
  10. Access2016学习16