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;
    }
    

      

  • 相关阅读:
    JAVA 问题
    WebStrom配置多个项目的Dweployment时,设置默认的启动配置
    C#中有关数组和string引用类型或值类型的判断
    Delegate(代理)异常:该委托必须有一个目标
    RMAN BACKUP
    Oracle ORA-01033: 错误解决办法
    微信公众号开发 接口配置信息 配置失败
    使用JAVA开发微信公众平台(一)——环境搭建与开发接入
    微信开发准备(四)--nat123内网地址公网映射实现
    nat123安装启动教程帮助
  • 原文地址:https://www.cnblogs.com/c-slmax/p/5253375.html
Copyright © 2011-2022 走看看