在socket编程中,我们时常要设置socket套接字相关选项,设置不同的选项要调用的函数可能是不一样的,比如ioctlsocket、setsockopt和WSAIoctl函数。这三个函数很容易混淆,今天我们就来讲讲这几个函数主要是用来设置哪些选项的。
ioctlsocket函数主要是用来设置或取消非阻塞套接字的。将套接字设置为非阻塞式套接字后,connect、send和recv等函数将变成非阻塞式的,调用后会立即返回,执行的操作结果成功与否,需要通过后续代码去判断。
设置非阻塞式套接字的代码如下:
unsigned long unblock = 1;
int ret = ioctlsocket(tSock, FIONBIO, (unsigned long *)&unblock);
setsockopt可以用来设置套接字的一系列选项,最常用的是用来设置接收缓冲区和发送缓冲区大小的,如下所示:
// 设置发送缓冲区大小
int optVal = 2*1024*1024; // 2MB
setsockopt(tSock, SOL_SOCKET, SO_SNDBUF, (char *)&optVal, sizeof(optVal));
// 设置接收缓冲区大小
optVal = 2*1024*1024; // 2MB
setsockopt(tSock, SOL_SOCKET, SO_RCVBUF, (char *)&optVal, sizeof(optVal));
WSAIoctl则主要用来设置TCP连接的心跳参数的,这个心跳参数是属于TCPIP协议栈中的。设置的心跳参数对应如下的结构体:
/* Argument structure for SIO_KEEPALIVE_VALS */
struct tcp_keepalive {
u_long onoff;
u_long keepalivetime;
u_long keepaliveinterval;
};
其中,keepalivetime 成员用来指定在发送第一个 keep-alive 数据包后到发送下个keep-alive 数据包之间的间隔时间(以毫秒为单位)。 keepaliveinterval 成员用来指定当发送keep-alive 数据包后未收到确认消息超时时发送连续 keep-alive 数据包之间的间隔(以毫秒为单位)。
在设置心跳参数之前,要先调用setsockopt打开心跳包设置选项。相关代码如下所示:
// 先调用setsockopt打开发送心跳包(设置)选项
int optval = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&optval, optlen) < 0)
return 1;
// 设置心跳参数
struct tcp_keepalive alive;
alive.onoff = TRUE;
alive.keepalivetime = 10*1000;
alive.keepaliveinterval = 10*1000;
DWORD dwBytesRet;
WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0, &dwBytesRet, NULL, NULL))
有人可能会说,不是还有个心跳包探测次数的设置参数吗?上述结构体tcp_keepalive中并没有这个参数,那是因为Windows操作系统中的心跳探测次数是固定为10次,是不可修改的。Linux系统中是可以修改的。