概述
socket
超时有三种处理办法:
- 使用alarm定时器,设置一定的超时时间,通过产生
SIGALRM
中断信号实现socket的超时中断。 - 利用
select
函数的超时功能,阻塞在select
的调用上代替阻塞在read或write
函数上 - 使用
SO_RCVTIMEO
和SO_SNDTIMEO
的socket选项
通过alarm定时器实现
- alarm的超时时间不能大于connect自身的超时时间
- 多线程场景很难处理
#include <unp.h>
static void connect_alarm(int);
int
connect_timeo(int sockfd, const sockaddr *saptr, socklen_t salen, int nsec)
{
sigfunc *sigfunc;//原始信号处理函数地址
int n;
sigfunc = signal(SIGALRM, connect_alarm);
if (alarm(nsec) != 0) {//返回值大于0表示:alarm已经设置过了,返回剩余时间
err_msg("connect_timeo: alarm war already set");
}
if ((n = connect(sockfd, saptr, salen)) < 0) {//中断来了,connect会立即返回,同时errno设置成EINTR
close(sockfd);
if (errno == EINTR) {
errno = ETIMEDOUT;
}
}
alarm(0);//恢复alarm
signal(SIGALRM, sigfunc);//恢复signal
return(n);
}
static void
connect_alarm(int signo)
{
return;
}
通过select实现
#include "unp.h"
int
readable_timeo(int fd, int sec)
{
fd_set rset;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(fd, &rset);
tv.tv_sec = sec;
tv.tv_usec = 0;
return(select(fd + 1, &rset, NULL, NULL, &tv));
}
出错时返回-1,超时时返回0,否则返回正数,表示已经就绪的描述符数目。
通过SO_RCVTIMEO和SO_SNDTIMEO实现
struct timeval tv;
int sockfd;
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
选项SO_RCVTIMEO
和SO_SNDTIMEO
传参为struct timeval
类型的参数,分别用于设置接收和发送的函数的超时时间。
- 影响的接收函数:write, writev, send, sendto, sendmsg
- 影响的发送函数:read, readv, recv, recvfrom, recvmsg
超时时,errno被设置为EAGAIN或EWOULDBLOCK。仅对阻塞模式的socket有效,非阻塞模式的socket调用上面的函数还是立即返回。