• Window+TCP+connect 超时阻塞解决办法


    现象:一般情况下,connect是以阻塞模式进行工作的,但如果在S/C架构开发中,如果S端没有开启,而C端去connect一个未开启或不存在的S时,就
    会出现“卡死”的现象。

    原因:
    客户端在连接服务器时,可能会出现问题,导致三次握手无法完成,持续重试,表现在客户端程序的行为就是卡在connect调用上无法返回。在一个
    TCP套接口被设置为非阻塞之后调用connect,connect会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未完成;同时TCP的三路握手操作
    继续进行;在这之后,我们可以调用select来检查这个链接是否建立成功;


    解决方法
    1.建立socket
    2.将该socket设置为非阻塞模式
    3.调用connect()
    4. 判断返回值是否是WSAEWOULDBLOCK,(在vs2015或linux下,应该是EINPROGRESS,没有试)
    5.如果4成立,使用select()检查该socket描述符是否可写
    6.如果5成立,则说明连接成功,将socket重设置为阻塞模式

    附,网上还有一种说法是,第5步使用getsockopt来获取错误,如果不存在错误(错误值为0),则连接成功,但本人没有成功。

    VC6++参考代码

     1 int SKTCPSocket::connectHost(char *ip, const unsigned int port)
     2 {
     3     int ret=0;
     4     timeval tm={2,0};  
     5     fd_set rset; 
     6     fd_set wset; 
     7     unsigned long mode = 1;  
     8 
     9     SOCKADDR_IN addrSrv;
    10     addrSrv.sin_addr.S_un.S_addr = inet_addr(ip);
    11     addrSrv.sin_family = AF_INET;
    12     addrSrv.sin_port = htons(port);
    13 
    14     mode = 1;
    15     ret=ioctlsocket(m_clientSocket, FIONBIO, &mode); /*!<设置为非阻塞模式,成功返回0 */
    16     if(ret)
    17     {
    18         closesocket(m_clientSocket);
    19         return -1;  
    20     }
    21 
    22     ret=connect(m_clientSocket, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));/*!<成功返回0,但在非阻塞情况下,一般为-1*/
    23     if(ret)
    24     {
    25         ret=WSAGetLastError();
    26         if(WSAEWOULDBLOCK==ret)/*!<如果Resource temporarily unavailable.10035*/
    27         {
    28             FD_ZERO(&rset); 
    29             FD_ZERO(&wset); 
    30             FD_SET(m_clientSocket, &rset);
    31             FD_SET(m_clientSocket, &wset);
    32 
    33             ret=select(m_clientSocket+1, &rset, &wset, NULL, &tm) ;
    34             if(ret<0)
    35             {
    36                 closesocket(m_clientSocket);
    37                 return -2; 
    38             }
    39             else if(ret==0)/*!<Time Out*/
    40             {
    41                 closesocket(m_clientSocket);
    42                 return -3; 
    43             }
    44             else
    45             {
    46                 if(FD_ISSET(m_clientSocket,&wset))/*!<如果可写,说明连接好*/
    47                 {
    48                     mode = 0;  
    49                     ret=ioctlsocket(m_clientSocket, FIONBIO, &mode); /*!<再次设置为阻塞模式 */ 
    50                     if(ret)   
    51                     {  
    52                         closesocket(m_clientSocket);
    53                         return -4;  
    54                     } 
    55                     /*!<正确退出*/
    56                     return 0;  
    57                 }
    58                 else
    59                 {
    60                     /*!<不可写*/
    61                     closesocket(m_clientSocket);
    62                     return -5;
    63                 }
    64                 
    65             }
    66         }//    end if(WSAEWOULDBLOCK==ret)
    67         else
    68         {
    69             /*!<网络出现其他错误*/
    70         closesocket(m_clientSocket);
    71         return -6; 
    72         }
    73     }
    74     else
    75     {
    76         return 0;
    77     }
    78 }

    参考:
    http://olive101.blog.163.com/blog/static/2051263201011221915696/
    http://blog.csdn.net/saspss/article/details/8487678
    http://blog.csdn.net/u014805066/article/details/50592415

  • 相关阅读:
    从头到尾彻底理解KMP
    [CF1220E] Tourism
    [CF446C] DZY Loves Fibonacci Numbers
    [CF1003E] Tree Constructing
    [CF1238E] Keyboard Purchase
    [CF915E] Physical Education Lessons
    [CF788B] Weird journey
    [CF1371E2] Asterism (Hard Version)
    [CF780E] Underground Lab
    [CF372C] Watching Fireworks is Fun
  • 原文地址:https://www.cnblogs.com/gjianw217/p/6297023.html
Copyright © 2020-2023  润新知