一.超时引用必要性
在网络通信中,很多操作会使得进程阻塞例如
TCP套接字中的recv/accept/connect
UDP套接字中的recvfrom
你也不能一直阻塞着不干活啊, 避免进程在没有数据时无限制地阻塞,所以引入超时检测。
当设定的时间到时,进程从原操作返回继续运行。
二.设置超时的三种方法:
1. 设置socket的属性 SO_RCVTIMEO,我们上面讲的改属性
例:
设置接收超时:
struct timeval tout;
tout.tv_sec = 5;
tout.tv_usec = 0;
setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof (struct timeval));
2. 用select检测socket是否’ready’,也是我们学习select学过的。
例:
struct fd_set rdfs;
struct timeval tv = {5 , 0}; // 设置5秒时间
FD_ZERO(&rdfs);
FD_SET(sockfd, &rdfs);
if (select(sockfd+1, &rdfs, NULL, NULL, &tv) > 0) //
3. 设置定时器(timer), 捕捉SIGALRM信号,这个在讲信号章节的时候也有说到。
设置一个alarm信号,时间到了触发信号。
void handler(int signo) { return; }
struct sigaction act;
sigaction(SIGALRM, NULL, &act);
act.sa_handler = handler;
act.sa_flags &= ~SA_RESTART; //清除掉SIGALRM信号的SA_RESTART
sigaction(SIGALRM, &act, NULL);
alarm(5);
if (recv(,,,) < 0)
设置一个alarm信号,recv一直阻塞等待数据,当5s到来时,产生一个信号,打断recv的阻塞,去处理其他事情。
三.如何在linux中动态检测是否有网络,或者网络中途掉线?
1.应用层,使用心跳检测(客户端每过一段时间就给服务器发一个心跳包,告诉我还活着。)
2.我们的setsockopt属性修改参数中,有个SO_KEEPALIVE 保持连接的属性,它在不修改的情况下默认是2个小时检查一次连接。
int keepAlive = 1; //设定KeepAlive
int keepIdle = 5; //开始首次KeepAlive探测前的TCP空闭时间
int keepInterval = 5; //两次KeepAlive探测间的时间间隔
int keepCount = 3; //判定断开前的KeepAlive探测次数
setKeepAlive (newfd, keepAlive, keepIdle, keepInterval, keepCount);//这个函数内部调用了setsockopt函数。
来改变套接字的属性,来完成网络的检测。
这节看着内容不多,但是是非常重要的,超时的应用在我们之后的编程中使用的非常多,灵活的使用可以提高我们代码的执行效率,减少不必要的资源浪费。