socket概念
套接字(Socket)是计算机网络编程中的一个概念,用于在网络上进行通信。它是一种抽象的通信端点,可以通过网络进行数据的发送和接收。
套接字提供了一种统一的编程接口,使得应用程序可以通过网络进行数据的传输和通信。它通过网络传输层协议(如TCP、UDP等)实现数据的可靠传输或者不可靠传输。
套接字通常由以下几个要素组成:
-
IP地址:用于标识网络上的主机或者设备。
-
端口号:用于标识网络上的不同应用程序或者服务。
-
协议:用于指定网络传输层协议,如TCP、UDP等。
通过套接字,应用程序可以通过发送和接收数据报来进行通信。发送方将数据封装成数据报,并通过套接字发送给接收方,接收方通过套接字接收数据报并进行处理。
套接字编程是网络编程中常见的一种方式,它提供了丰富的接口和函数,用于创建、连接、发送、接收和关闭套接字等操作。在套接字编程中,可以实现各种类型的网络通信,如客户端-服务器模式、点对点通信等。
常用数据类型
const int BUF_SIZE = 32;
WSADATA wsd; //WSADATA变量
SOCKET sServer; //服务端套接字
SOCKET sClient; //客户端套接字
sockaddr_in addrServ; //服务端地址
char buf[BUF_SIZE]; //接收数据缓冲区
char str1[BUF_SIZE];
char sendBuf[BUF_SIZE];//返回给客户端的数据
char strJsonRecv[64];
int retVal; //返回值
string strJsonSend = "KEY_PileNo";
这段代码是一个简单的服务器端代码,用于接收客户端发送的数据,并返回给客户端一个字符串。具体解释如下:
-
const int BUF_SIZE = 32
:定义了一个常量BUF_SIZE
,表示接收数据缓冲区的大小为32字节。 -
WSADATA wsd
:定义了一个WSADATA
结构体变量wsd
,用于接收套接字库的初始化信息。 -
SOCKET sServer
和SOCKET sClient
:分别定义了服务端套接字和客户端套接字,用于接收和处理客户端的连接请求。 -
sockaddr_in addrServ
:定义了一个sockaddr_in
结构体变量addrServ
,用于存储服务端的地址信息。 -
char buf[BUF_SIZE]
、char str1[BUF_SIZE]
和char sendBuf[BUF_SIZE]
:分别定义了接收数据缓冲区、字符串变量和用于返回给客户端的数据缓冲区。 -
char strJsonRecv[64]
:定义了一个大小为64字节的字符数组strJsonRecv
,用于接收客户端发送的JSON数据。 -
int retVal
:定义了一个整型变量retVal
,用于存储函数调用的返回值。 -
string strJsonSend = "KEY_PileNo"
:定义了一个字符串变量strJsonSend
,并初始化为"KEY_PileNo",该字符串将作为返回给客户端的数据。
常用函数
WSAStartup()
WSAStartup(MAKEWORD(2,2), &wsd)
WSAStartup
是Windows套接字库提供的函数,用于初始化套接字库。MAKEWORD(2,2)
是一个宏,用于指定套接字库的版本号,这里是指定使用2.2版本的套接字库。&wsd
是一个指向WSADATA
结构体的指针,用于接收套接字库的初始化信息。WSAStartup
函数返回0表示初始化成功,如果返回值不为0,则表示初始化失败。
socket();
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
socket
函数用于创建一个套接字。AF_INET
表示使用IPv4地址族,SOCK_STREAM
表示创建一个面向连接的套接字,IPPROTO_TCP
表示使用TCP协议。常用if(INVALID_SOCKET == sServer)
判断socket
函数返回的套接字是否为无效套接字。INVALID_SOCKET
是一个宏,表示无效的套接字。
WSACleanup()
WSACleanup
函数用于释放套接字库所占用的资源,包括关闭套接字库并释放其它相关资源。
上面socket()套接字创建失败可能是由于系统资源不足或者套接字库初始化失败等原因。所以在失败后,往往会跟进一步WSACleanup
函数。
htons()
htons
函数用于将主机字节序的端口号转换为网络字节序的端口号。例如设置端口号:
addrServ.sin_port=htons(m_nPort); //设置端口号
m_nPort
是一个变量,表示要设置的端口号。通过调用htons
函数将主机字节序的端口号转换为网络字节序后,将结果赋值给addrServ.sin_port
,实现了设置端口号的操作。
网络字节序是一种统一的网络数据传输格式,不受不同主机字节序的影响,因此在套接字编程中常常需要进行字节序的转换。
bind()
retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
用于将套接字(socket)与指定的地址绑定起来。具体解释如下:
-
retVal
:retVal
是一个变量,用于接收bind()
函数的返回值。bind()
函数成功时返回0,失败时返回-1。 -
sServer
:sServer
是一个套接字描述符,表示要绑定的套接字。 -
(LPSOCKADDR)&addrServ
:&addrServ
表示指向addrServ
的指针,LPSOCKADDR
是指向SOCKADDR
结构体的指针,用于指定要绑定的地址。 -
sizeof(SOCKADDR_IN)
:sizeof(SOCKADDR_IN)
用于获取SOCKADDR_IN
结构体的大小,即要绑定的地址的长度。
通过调用bind()
函数将套接字与addrServ
所指定的地址绑定起来,将绑定结果赋值给retVal
,以便后续判断绑定是否成功。绑定后,该套接字就可以使用指定的地址进行通信。
类似的,如果绑定失败,是需要关闭套接字并释放资源的。
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
listen()
用于将套接字(socket)设置为监听状态,以便接受客户端的连接请求。例如
retVal = listen(sServer, 1);
具体解释如下:
-
retVal
:retVal
是一个变量,用于接收listen()
函数的返回值。listen()
函数成功时返回0,失败时返回-1。 -
sServer
:sServer
是一个套接字描述符,表示要设置为监听状态的套接字。 -
1
:1
表示设置监听队列的最大长度。这个参数指定了在调用listen()
函数后,等待连接的客户端能够排队的最大数量。在这个例子中,将最大排队长度设置为1,表示在某一时刻只能接受一个客户端的连接请求。
通过调用listen()
函数,将套接字设置为监听状态,以便开始接受客户端的连接请求。设置监听后,套接字将开始监听指定端口上的连接请求,并将这些请求排队等待处理。retVal
变量用于接收函数的返回值,以便后续判断监听是否成功。
accept()
sClient = accept(sServer,(sockaddr FAR*)&addrClient, &addrClientlen);
用于接受客户端的连接请求,并创建一个新的套接字来与客户端进行通信。具体解释如下:
-
sClient
:sClient
是一个套接字描述符,用于表示与客户端建立的新连接。 -
accept()
函数:accept()
函数用于接受客户端的连接请求,并创建一个新的套接字来与客户端进行通信。它的第一个参数sServer
是一个套接字描述符,表示正在监听的套接字。accept()
函数会从监听队列中选择一个连接请求,并返回一个新的套接字描述符,用于与客户端通信。 -
(sockaddr FAR*)&addrClient
:(sockaddr FAR*)&addrClient
是一个指向sockaddr
结构体的指针,用于存储客户端的地址信息。sockaddr
结构体是一个通用的套接字地址结构,可以根据实际情况使用不同的具体类型,如sockaddr_in
用于IPv4地址,sockaddr_in6
用于IPv6地址等。 -
&addrClientlen
:&addrClientlen
是一个整型变量的指针,用于传递客户端地址结构体的长度。在调用accept()
函数之前,需要将addrClientlen
初始化为socklen_t
类型的长度值。
通过调用accept()
函数,可以接受客户端的连接请求,并创建一个新的套接字sClient
来与客户端进行通信。新的套接字sClient
将成为与客户端之间的通信通道,可以通过该套接字进行数据的发送和接收。
setsockopt()
setsockopt
函数用于设置套接字选项的值。它的原型如下:
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
例如用它来设置套接字的发送超时时间:
int timeout = 6000;
int retSend=setsockopt(m_SocketClient,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout));
int retRecv=setsockopt(m_SocketClient,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout));
sockfd
:套接字描述符,用于标识要设置选项的套接字。level
:选项所属的协议层,常用的是SOL_SOCKET
表示套接字级别选项。optname
:选项的名称,常用的是SO_SNDTIMEO
表示发送超时时间选项、SO_RCVTIMEO
表示接收超时时间选项。optval
:选项的值,是一个指向选项值的指针。optlen
:选项值的长度。
在这个例子中,m_SocketClient
是要设置选项的套接字描述符。SOL_SOCKET
表示套接字级别选项,SO_SNDTIMEO
表示发送超时时间选项,SO_RCVTIMEO
表示接收超时时间选项。&timeout
是一个指向超时时间值的指针,sizeof(timeout)
表示超时时间值的长度。
recv()
retVal = recv(sClient, buf, BUF_SIZE, 0);
用于从客户端接收数据,并将接收到的数据存储在缓冲区buf
中。具体解释如下:
-
retVal
:retVal
是一个整型变量,用于存储recv()
函数的返回值。recv()
函数返回接收到的字节数,如果返回值为0,则表示客户端已关闭连接,如果返回值为-1,则表示接收出现错误。 -
recv()
函数:recv()
函数用于从指定的套接字sClient
接收数据。它的第一个参数sClient
是一个套接字描述符,表示要接收数据的套接字。第二个参数buf
是一个指向缓冲区的指针,用于存储接收到的数据。第三个参数BUF_SIZE
表示要接收的最大数据长度。第四个参数0
表示接收数据时不使用任何特殊的标志。
通过调用recv()
函数,可以从客户端接收数据,并将接收到的数据存储在缓冲区buf
中。recv()
函数将返回接收到的字节数,并将其赋值给retVal
变量。根据retVal
的值,可以判断接收是否成功,以及客户端是否已关闭连接。
send()
send(sClient,sendBuf,strlen(sendBuf),0);
send
函数是套接字编程中用于发送数据的函数。它的第一个参数是要发送数据的套接字描述符,第二个参数是一个指向要发送的数据的缓冲区的指针,第三个参数是要发送的数据的长度,第四个参数是发送操作的标志,0表示使用默认的发送选项。
ZeroMemory()
ZeroMemory(buf, BUF_SIZE);
ZeroMemory
函数:ZeroMemory
函数是Windows API提供的一个宏,用于将指定内存块的内容全部设置为零。它的第一个参数是要清零的内存块的指针,第二个参数是内存块的大小。
通过调用ZeroMemory
函数,可以将缓冲区buf
的内容全部清零,即将缓冲区的每个字节设置为0。这样可以确保在接收新的数据之前,缓冲区中没有之前接收到的旧数据。
strcpy_s()
strcpy_s(sendBuf, strlen(strJsonSend.c_str())+1, strJsonSend.c_str());
strcpy_s
函数是C语言中的字符串拷贝函数,用于将一个字符串复制到另一个字符串。它的第一个参数是目标字符串的指针,第二个参数是目标字符串的大小,第三个参数是要复制的源字符串的指针。在这里,strlen(strJsonSend.c_str())+1
表示源字符串的长度加上一个字节,用于存储字符串的结束符\0
。