connect调用被信号中断问题解决方法

举报
向巴菲特学习 发表于 2021/05/14 16:23:40 2021/05/14
【摘要】 慢系统调用connect返回EINTR错误时,不能再次调用它,否则将立即返回一个错误,原因是:connect的请求已经发送向对方,正在等待对方回应,这时如果重新调用connect,由于对端已经接受了上次的connect请求,这一次的connect就会被拒绝,因此,需要使用select或poll调用来检查socket的状态,如果socket的状态就绪,则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;
    }
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。