在网络通信中,很多操作会使得进程阻塞
1.TCP套接字中的recv/accept/connect
2.UDP套接字中的recvfrom
超时检测的必要性
1.避免进程在没有数据时无限制地阻塞
2.当设定的时间到达时,进程会从原操作返回继续运行
以下是网络超时检测的3种设置方法
1-- 使用setsockopt 进行超时设置
struct timeval
{
__time_t tv_sec; /* Seconds. */ 秒
__suseconds_t tv_usec; /* Microseconds. */ 微秒 };
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
设置超时检测
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0){
err_log("fail to setsockopt");
}
2-- 使用select 函数实现超时检测
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
功能:允许一个进程监听多个文件描述符集合,阻塞等待,直到有一个或者多个文件描述符资源准备就绪,那么函数立刻返回。
参数:nfds 最大的文件描述符加1
readfds 读文件描述符集合
writefds 写文件描述符集合
exceptfds 异常的文件描述符集合
timeout 如果设置为NULL,则一直阻塞等待
返回值:成功 timeout 为 NULL 时 ,已经准备就绪的文件描述符的个数
timeout 不为NULL时 ,时间到达之前,有文件描述符准备就绪,那 么返回准备就绪的文件描述符的个数时间到达之前,没有文件描述符
准备就绪那么返回0
出错 -1
注意:每次select之后成功之后,都会将集合中没有准备就绪的文件
描述符给清楚掉,所以需要每次重新添加
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
ret = select(maxfd+1, &readfds, NULL, NULL, &tv);
注意:每次调用select 函数之前,都应该对tv进行重新赋值
3-- 使用alarm 定时器 ,实现超时检测
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
功能:注册一个信号,设置信号的属性信息
参数: signum 信号,不能是 SIGKILL , SIGSTOP
act 信号新的属性行为
oldact 信号当前的属性行为
返回值: 成功 0
出错 -1
struct sigaction {
void (*sa_handler)(int); // 信号处理函数
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags; // SA_RESTART 系统调用的自重启属性。
void (*sa_restorer)(void);
};
struct sigaction act;
// 注册闹钟信号
sigaction(SIGALRM, NULL, &act);
act.sa_handler = handler; // 设置信号处理函数
act.sa_flags &= ~SA_RESTART; //设置自重启属性为假
sigaction(SIGALRM, &act, NULL);
alarm(5);