概述
【1】网络超时检测的定义
在网络通信中,很多操作会使得进程阻塞
TCP套接字中的recv/accept
UDP套接字中的recvfrom
超时检测的必要性
避免进程在没有数据时无限制地阻塞
当设定的时间到时,进程从原操作返回继续运行
【2】实质
阻塞函数,当缓冲区或者文件里面没有数据写入,则会一直阻塞直到有数据为止。
非阻塞,及时缓冲区或者文件里面没有数据,也会立即返回,接着往下执行 超时检测,设定一定的时间,在时间范围之内,一直阻塞等待数据的写入,如果时间到时还没有数据,则立即返回,变成非阻塞状态
网络超时检测,当客户端连接服务器,服务器端会开辟一块空间与客户端进行通信,如果客户端在连接之后不与服务器进行通信,则会浪费服务器资源,所以使用超时 将其断开连接,节省服务器资源
【3】方法1:使用setsockopt实现网络超时检测
int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);
功能:设置套接字的选项
参数:
socket:文件描述符
level:协议层次
SOL_SOCKET 套接字层次
option_name:选项的名称(套接字层次)
SO_RCVTIMEO 设置接收超时时间
option_value:设置的选项的值
struct timeval {
__kernel_time_t tv_sec; 秒
__kernel_suseconds_t tv_usec; 微秒
};
option_len:value的长度
返回值:
成功:0
失败:-1
使用setsockopt设置的超时时间,设置一次,永久有效。对所有和网络相关的阻塞函数有效
定义结构体变量,并设置超时检测时间5秒
struct timeval time_out;
time_out.tv_sec=5;
time_out.tv_usec=0;
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &time_out, sizeof(time_out)) < 0)
{
perror("fail to setsockopt");
}
while(1)
{
//阻塞等待客户端的连接
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
{
//printf("errno = %dn", errno);
//超时之后返回的错误码是11。
if(errno == 11)
{
//超时打印
printf("连接超时...n");
}
else
{
perror("fail to accept");
}
}
【4】方法二:使用select函数实现网络超时检测
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:同步一个io操作,允许一个程序处理多个文件描述符,阻塞等待文件描述符准备就绪,如果有一个或者多
个文件描述符准备就绪,则函数立即返回,并执行相应的io操作
参数:
nfds:最大的文件描述符加1
readfds:读文件描述符集合
writefds:写文件描述符集合
exceptfds:其他或者异常的文件描述符集合
timeout:超时
struct timeval { __kernel_time_t tv_sec; 秒
__kernel_suseconds_t tv_usec; 微秒
};
0 非阻塞
NULL 阻塞
返回值:
成功:准备就绪的文件描述符的个数
失败:-1
void FD_ZERO(fd_set *set);
清空一个集合set
void FD_SET(int fd, fd_set *set);
将文件描述符fd添加到集合set里面
void FD_CLR(int fd, fd_set *set);
将文件描述符fd从集合set里面移除
int FD_ISSET(int fd, fd_set *set);
判断文件描述符fd是否在集合set里面
该函数也是永久有效
fd_set readfds;
int maxfd,ret,i;
struct timeval time_out;
//第一步清空集合
FD_ZERO(&readfds);
//第二步将需要的文件描述符添加到集合里
FD_SET(sockfd,&readfds);
maxfd=sockfd; //当前最大描述符值
while(1)
{
time_out.tv_sec = 5;
time_out.tv_usec = 0;
//调用select函数阻塞等待文件描述符准备就绪
if((ret = select(maxfd + 1, &tempfds, NULL, NULL, &time_out)) < 0)
{
errlog("fail to select");
}
//返回值为0时代表超时
else if(ret == 0)
{
printf("time out...n");
}
}
【5】方法3:使用alarm闹钟实现网络超时检测
alarm闹钟,当设定一定个的时间之后,代码接着往下运行,当时间到达时候,会退出进程如果结合信号,当闹钟响时,会触发SIGALRM信号,执行信号处理函数,当信号处理函数执行完毕,会接着刚才的代码继续执行,这一属性,称之为自重启属性,如果想实现网络超时检测,需要关闭这一属性
使用sigaction函数设置信号的行为
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
功能:获取或者修改一个信号的行为
参数:
signum:信号
act:新的行为
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); 没有用
};
oldact:旧的行为
返回值:
成功:0
失败:-1
//第一步:读取信号的行为
struct sigaction act;
if(sigaction(SIGALRM, NULL, &act) < 0)
{
perror("fail to sigaction");
return -1;
}
//第二步:修改信号的行为
act.sa_handler = handler;
act.sa_flags = act.sa_flags & (~SA_RESTART);
//第三步:将新的行为写回去
if(sigaction(SIGALRM, &act, NULL) < 0)
{
perror("fail to sigaction");
return -1;
}
while(1)
{
alarm(5); //定时5秒
//阻塞等待客户端的连接请求
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
{
//printf("errno = %dn", errno);
//延时错误码为4
if(errno == 4)
{
printf("连接超时...n");
}
else
{
errlog("fail to accept");
}
}
最后
以上就是积极蓝天为你收集整理的简单的几种网络超时检测的全部内容,希望文章能够帮你解决简单的几种网络超时检测所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复