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写入文本文件
    oracle误删数据闪回
    Myeclipese :Creation of element failed解决方法
    Hibernate的四种状态
    java中list、set和map 的区别<转>
    C#操作mysql中临时表不自动删除
    WPF 实现地图的移动和滚动放大
    c# 将十六进制字符串写入注册表
    ASP.NET 视图状态概述:初步了解
    vs好用插件
  • 原文地址:https://www.cnblogs.com/c-slmax/p/5253375.html
Copyright © 2011-2022 走看看