zoukankan      html  css  js  c++  java
  • 关于非阻塞connect的若干细节性问题

    我们用man connection命令查看手册,如下:
     
    1. EINPROGRESS
    2. The socket is nonblocking and the connection cannot be completed immediately. It
    3. is possible to select(2) or poll(2) for completion by selecting the socket for
    4. writing. After select(2) indicates writability, use getsockopt(2) to read the
    5. SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error
    6. codes listed here, explaining the reason for the failure).
    当connect可写时还可能是发生了错误,我们必须判断这种情况。发生错误时套接字既可读又可写,而connect连接成功时套接字也可能即可读又可写(select之前有可能连接已经建立并有来自对端的数据到达).
     
    如何区分这两种情况呢?因此,必须调用

    1. getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len)
    另一个问题,对于非阻塞式套接字,如果其上的connect调用被信号中断并且不会由内核自动重启,那么它将返回EINTR,此时我们不能再次调用connect等待未完成的连接继续完成,这样做将导致返回EADDRINUSE错误。我们只能调用select检测其状态,就像上面说的那样。
     
     
    int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
    {
    	int ret;
    	socklen_t addrlen = sizeof(struct sockaddr_in);
    
    	if (wait_seconds > 0)
    		activate_nonblock(fd); //设为非阻塞
    
    	ret = connect(fd, (struct sockaddr*)addr, addrlen);
    	if (ret < 0 && errno == EINPROGRESS)
    	{
    		//printf("11111111111111111111
    ");
    		fd_set connect_fdset;
    		struct timeval timeout;
    		FD_ZERO(&connect_fdset);
    		FD_SET(fd, &connect_fdset);
    		timeout.tv_sec = wait_seconds;
    		timeout.tv_usec = 0;
    		do
    		{
    			// 一但连接建立,则套接字就可写  所以connect_fdset放在了写集合中
    			ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout);
    		} while (ret < 0 && errno == EINTR);
    		if (ret == 0)
    		{
    			ret = -1;
    			errno = ETIMEDOUT;
    		}
    		else if (ret < 0)
    			return -1;
    		else if (ret == 1)
    		{
    			//printf("22222222222222222
    ");
    			/* ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*/
    			/* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */
    			int err;
    			socklen_t socklen = sizeof(err);
    			int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen);
    			if (sockoptret == -1)
    			{
    				return -1;
    			}
    			if (err == 0)
    			{
    				//printf("3333333333333
    ");
    				ret = 0;
    			}
    			else
    			{
    				//printf("4444444444444444:%d
    ", err);
    				errno = err;
    				ret = -1;
    			}
    		}
    	}
    	if (wait_seconds > 0)
    	{
    		deactivate_nonblock(fd);   //设回阻塞
    	}
    	return ret;
    }
    

      

  • 相关阅读:
    es index template
    什么是元类
    Normal Data Structure Tricks
    Python 学习笔记
    点分治
    人类智慧贪心
    「JOI 2021 Final」地牢 3
    【美团杯2020】魔塔
    CF917D 的垃圾做法
    【ULR #2】Picks loves segment tree IX
  • 原文地址:https://www.cnblogs.com/c-slmax/p/5253375.html
Copyright © 2011-2022 走看看