connect调用被信号中断问题解决方法
系统调用被分为慢系统调用和其他两大类别,慢系统调用可以被永久阻塞。
当一个慢系统调用阻塞期间捕捉到一个信号, 则该系统调用就被中断不再继续执行。 该系统调用返回错误,且errno设置为EINTR。
当碰到EINTR错误的时候,有一些可以重启的系统调用要进行重启,而对于有一些系统调用是不能够重启的。例如:accept、read、write、select、和open之类的函数来说,是可以进行重启的。不过对于套接字编程中的connect函数我们是不能重启的,若connect函数返回一个EINTR错误的时候,我们不能再次调用它,否则将立即返回一个错误,原因是:connect的请求已经发送向对方,正在等待对方回应,这是如果重新调用connect,由于对方已经接受了上次的connect请求,这一次的connect就会被拒绝,因此,需要使用select或poll调用来检查socket的状态,如果socket的状态就绪,则connect已经成功,否则,视错误原因,做对应的处理。
针对connect不能重启的处理方法有两种。
方法一:
关闭当前socket,重新创建socket,调用connect接口建立tcp连接,代码示例如下。
reconnect:
int fd = socket(...);
int err = connect(fd, ... );
if (err == 0) {
printf("success");
return fd; //connect success
} else if (errno == EINTR) {
close(fd);
fd = -1;
goto reconnect; // interrupted by signal, reconnect
} else {
return -1; // connect failed
}
方法二:
当connect遇到EINTR错误时,进一步校验,需要使用select或poll调用来检查socket的状态,如果socket的状态就绪,则connect已经成功,否则,视错误原因,做对应的处理。
代码示例如下:
int check_conn_is_ok(socket_t sock) {
struct pollfd fd;
int ret = 0;
socklen_t len = 0;
fd.fd = sock;
fd.events = POLLOUT;
while ( poll (&fd, 1, -1) == -1 ) {
if( errno != EINTR ){
perror("poll");
return -1;
}
}
len = sizeof(ret);
if ( getsockopt (sock, SOL_SOCKET, SO_ERROR,
&ret,
&len) == -1 ) {
perror("getsockopt");
return -1;
}
if(ret != 0) {
fprintf (stderr, "socket %d connect failed: %s\n",
sock, strerror (ret));
return -1;
}
return 0;
}
/* connect返回-1且errno==EINTR时,调用check_conn_is_ok()进一步校验*/
if(connnect()) {
if(errno == EINTR) {
if(check_conn_is_ok() < 0) {
perror();
return -1;
}
else {
printf("connect is success!\n");
}
}
else {
perror("connect");
return -1;
}
}
- 点赞
- 收藏
- 关注作者
评论(0)