在TCP连接中,recv等函数默认为阻塞模式(block),即直到有数据到来之前函数不会返回,而我们有时则需要一种超时机制使其在一定时间后返回而不管是否有数据到来,这里我们就会用到setsockopt()函数:
int setsockopt(int s, int level, int optname, void* optval, socklen_t* optlen);
s(套接字): 指向一个打开的套接口描述字
level:(级别): 指定选项代码的类型。
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname(选项名):当级别为通用套接字选项SOL_SOCKET时
1、SO_REUSERADDR 允许重用本地地址和端口 int; 这个设置常在服务器中使用。例如:某个服务器进程占用了TCP的80端口进行侦听,当再次在此端口侦听的时候,会返回错误,那么设置SO_REUSERADDR可以解决这个问题,允许共用这个端口。某些非正常退出的服务器程序,可能需要占用端口一段时间才能允许其他进程使用,即使这个程序已经死掉了。内核仍然需要一段时间才能释放这个端口。一般这个时间为2分钟。
2、SO_RCVTIMEO 接收超时 struct timeval
3、SO_SNDTIMEO 发送超时 struct timeval
4、SO_BROADCAST 允许发送广播数据 int ; 适用于 UDP socket。其意义是允许 UDP socket 「广播」(broadcast)讯息到网路上(套接字默认不允许发送广播包)。 为了防止一些程序并不是设计用来发送广播消息,因为用户的错误输入,而发送了广播消息,比如一个UDP 程序接受一个目标IP地址做为命令行参数,但用户却把这个地址写成了一个广播地址这时候这个选项的作用就体现出来了,与其让这个UDP程序检验用户输入的是不是个广播地址,不如让内核来检测,如果是一个广播地址,但SO_BROADCAST 选项却没有被设定, EACCES错误就会被返回
5、SO_RCVBUF:在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int)); // 接收缓冲区
6、SO_SNDBUF:
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int)); //发送缓冲区
当级别为通用套接字选项IPPROTO_IP时:
IP_ADD_MEMBERSHIP 将ip添加到组 struct ip_mreq
struct ip_mreq merq;
merq.imr_multiaddr.s_addr = inet_addr("234.234.234.234");
merq.imr_interface.s_addr = inet_addr("192.168.50.6");
setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&merq,sizeof(merq));
optval(选项值):是一个指向变量的指针 类型:整形,套接口结构, 其他结构类型:linger{}, timeval{ }
optlen(选项长度) :optval 的大小
这里我们要涉及到一个结构:
struct timeval
{
time_t tv_sec;
time_t tv_usec;
};
这里第一个域的单位为秒,第二个域的单位为微秒。
struct timeval tv_out;
tv_out.tv_sec = 1;
tv_out.tv_usec = 0;
填充这个结构后,我们就可以以如下的方式调用这个函数:
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out));(具体参数可以man一下,或查看MSDN)
这样我们就设定了recv()函数的超时机制,当超过tv_out设定的时间而没有数据到来时recv()就会返回0值。