在网络编程中超时检测是一个比较常见的操作,因为网络连接具有很大的不确定性,而很多网络操作函数默认都是阻塞式的,因此如果不设置超时,可能会造成永久等待状态出现。
设置套接字选项
setsockopt
【注意】如果程序一直执行,设置的套接字选项一直有效,对所有跟套接字描述符相关的操作都有效
int setsockopt(int socket, int level, int option_name,
const void *option_value, socklen_t option_len);
功能: 用来设置套接字选项
参数:
socket 对哪一个套接字描述符进行设置
level 对哪一个层次进行设置(应用层、网络层、传输层)
1)SOL_SOCKET:通用套接字选项.
2)IPPROTO_IP:IP选项.
3)IPPROTO_TCP:TCP选项.
option_name 指定对应选项操作,具体查看手册
man 3 setsockopt
SO_RCVTIMEO 超时检测的选项
SO_SNDBUF 发送缓冲区大小
SO_RCVBUF 接收缓冲区大小
SO_BROADCAST 设置广播方式
。。。
option_value 设置对应的option_name的值是多少?
时间值得一个结构体
struct timeval {
__kernel_time_t tv_sec; /* seconds 秒数 */
__kernel_suseconds_t tv_usec; /* microseconds 微秒数*/
};
【注意】这两个值必须同时设置
option_len 是用来设定option_value这个指针变量所指向的变量的大小是多少?
option_len = sizeof(struct timeval)
通过select函数检测描述符
【注意】select设置的时间值只能一次有效,如果想要长期有效,必须经过多次设置
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能: 使用select检测多路文件描述符,条件满足立刻返回,否则阻塞
参数:
nfds 获取的有效的最大描述符 加 1
readfds 读描述符集合(里面存放的是可以读入数据的描述符)
fd_set里面是一个数组,用来存放描述符
writefds 写描述符集合
exceptfds 异常描述符集合
timeout 延时
struct timespec {
long tv_sec; /* seconds 设置秒数 */
long tv_nsec; /* nanoseconds 设置微妙数 */
};
【注意】两者必须同时设置,才能生效
返回值:
成功 返回有效描述符的个数
失败 -1
通过alarm函数并处理SIGALRM信号
这里涉及到信号的一个使用技巧。因为设置信号处理函数之后,当信号到来的时候,实际上是以中断的方式进入信号处理函数执行操作。如果信号到来的时候有一个函数调用处于阻塞状态,默认情况下执行完信号处理函数会回到阻塞状态,但是通过设置相应的参数,可以实现这样的效果:用alarm函数定时发送一个SIGALARM信号,执行完信号处理函数之后,原来的阻塞状态会被打破,同时返回一个EINTR错误码,然后我们在阻塞函数的后面检测这个错误码就可以实现超时检测功能。
【注意】alarm设置的时间值只能一次有效,如果想要长期有效,必须经过多次设置
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_RESATRT 自动重启属性
(本身信号的SIGALRM默认操作是结束进程,但是改变信号的属性之后,让程序重新回到系统调用中断 的地方accept 、 recv)
void (*sa_restorer)(void);
};
oldact 获取信号信息
sigaction() returns 0 on success and -1 on error
成功 0
失败 -1
sigaction使用原则:
1、获取信息
2、修改信息
3、重新设置信息