zoukankan      html  css  js  c++  java
  • Socket 阻塞

    我想用UDP阻塞模式给硬件设备发包,然后收包。因为网络的问题,经常丢包,也就是发了之后没有响应。这样的话,recvfrom会一直停在那里,死机了一样。
     
    //连接超时  
              //--------------------------------------------------------------------------  
              //设置为非阻塞方式连接  
              unsigned   long   ul   =   1;  
              int   ret   =   ioctlsocket(m_sSocket,   FIONBIO,   (unsigned   long*)&ul);  
              if(ret   ==   SOCKET_ERROR)  
              {  
                      err   =   WSAGetLastError();  
          closesocket(m_sSocket);  
          m_sSocket   =   NULL;  
          return   FALSE;  
              }  
       
     Struct timeval   timeout   ;     //   超时结构  
              fd_set  r;                                              
       
              FD_ZERO(&r);  
              FD_SET(m_sSocket,   &r);  
              timeout.tv_sec   =   iTimeout;       //   连接超时设置  
              timeout.tv_usec   =0;  
       
              connect(m_sSocket,(LPSOCKADDR)&server,sizeof(SOCKADDR));  
              ret   =   select(0,   0,   &r,   0,   &timeout);      
              if   (   ret   <=   0   )  
              {  
          err   =   WSAGetLastError();  
          closesocket(m_sSocket);  
          m_sSocket   =   NULL;  
          return   FALSE;  
              }  
       
        //设回阻塞模式  
              ul   =   0   ;  
              ret   =   ioctlsocket(m_sSocket,   FIONBIO,   (unsigned   long*)&ul);  
              //--------------------------------------------------------------------------  
       
       
                    //接收超时  
              //-------------------------------------------  
              //接收超时设置  
              struct                   timeval   outtime   ;     //   超时结构  
       
              FD_SET   fdr   =   {1,   m_sSocket};    
              outtime.tv_sec   =   timeout;      
              outtime.tv_usec   =0;  
              int   nSelectRet;  
              //------------------------------------------------------------  
              //网络只认单字节串,而EVC里多字节;发送的UNICODE串转换成单字节串  
              UINT   nLen   =   len   *   2;  
              char   *pByte   =   new   char[nLen+1];  
              memset(pByte,   0,   nLen+1);  
              WideCharToMultiByte(CP_ACP,   NULL,   buf,   wcslen(buf),pByte,   nLen,   NULL,   NULL);  
              int   nRet;  
       
              nSelectRet=::select(0,   &fdr,   NULL,   NULL,   &outtime);   //检查可读状态    
              if(SOCKET_ERROR==nSelectRet)    
              {  
        err   =   WSAGetLastError();  
        closesocket(m_sSocket);  
        m_sSocket   =   NULL;  
        return   -1;  
              }  
              if(nSelectRet==0)   //超时发生,无可读数据    
              {  
        AfxMessageBox(L"接收超时");  
        err   =   WSAGetLastError();  
        closesocket(m_sSocket);  
        m_sSocket   =   NULL;  
        return   -1;  
              }  
              else    
              {  
        //接收数据  
        nRet   =   recv(m_sSocket,   pByte,   nLen,   0);  
        if(nRet   ==   SOCKET_ERROR)  
        {  
          err   =   WSAGetLastError();  
        }  
              }  
       
              //-------------------------------------------  
       
              MultiByteToWideChar(CP_ACP,   NULL,   pByte,   nLen,   buf,   len);  
              delete   []   pByte;  
              pByte   =   NULL;  
     
    不知道大家有没有遇到过这种情况,当socket进行TCP连接的时候(也就是调用connect时),一旦网络不通,或者是ip地址无效,就可能使整个线程阻塞。一般为30秒(我测的是20秒)。如果设置为非阻塞模式,能很好的解决这个问题,我们可以这样来设置非阻塞模式:调用ioctlsocket函数: unsigned long flag=1; if (ioctlsocket(sock,FIONBIO,&flag)!=0) { closesocket(sock); return false; } 以下是对ioctlsocket函数的相关解释: int PASCAL FAR ioctlsocket( SOCKET s, long cmd, u_long FAR* argp); s:一个标识套接口的描述字。 cmd:对套接口s的操作命令。 argp:指向cmd命令所带参数的指针。 注释: 本函数可用于任一状态的任一套接口。它用于获取与套接口相关的操作参数,而与具体协议或通讯子系统无关。支持下列命令: FIONBIO:允许或禁止套接口s的非阻塞模式。argp指向一个无符号长整型。如允许非阻塞模式则非零,如禁止非阻塞模式则为零。当创建一个套接口时,它就处于阻塞模式(也就是说非阻塞模式被禁止)。这与BSD套接口是一致的。WSAAsynSelect()函数将套接口自动设置为非阻塞模式。如果已对一个套接口进行了WSAAsynSelect() 操作,则任何用ioctlsocket()来把套接口重新设置成阻塞模式的试图将以WSAEINVAL失败。为了把套接口重新设置成阻塞模式,应用程序必须首先用WSAAsynSelect()调用(IEvent参数置为0)来禁至WSAAsynSelect()FIONREAD:确定套接口s自动读入的数据量。argp指向一个无符号长整型,其中存有ioctlsocket()的返回值。如果sSOCKET_STREAM类型,则FIONREAD返回在一次recv()中所接收的所有数据量。这通常与套接口中排队的数据总量相同。如果SSOCK_DGRAM 型,则FIONREAD返回套接口上排队的第一个数据报大小。 SIOCATMARK:确实是否所有的带外数据都已被读入。这个命令仅适用于SOCK_STREAM类型的套接口,且该套接口已被设置为可以在线接收带外数据(SO_OOBINLINE)。如无带外数据等待读入,则该操作返回TRUE真。否则的话返回FALSE假,下一个recv()recvfrom()操作将检索标记前一些或所有数据。应用程序可用SIOCATMARK操作来确定是否有数据剩下。如果在紧急(带外)数据前有常规数据,则按序接收这些数据(请注意,recv()recvfrom()操作不会在一次调用中混淆常规数据与带外数据)。argp指向一个BOOL型数,ioctlsocket()在其中存入返回值。 此时已经设置非阻塞模式,但是并没有设置connect的连接时间,我们可以通过调用select语句来实现这个功能。以下代码设定了是连接时间为5秒,如果还未能连上,则直接返回。 struct timeval timeout ; fd_set r; int ret; connect( sock, (LPSOCKADDR)sockAddr, sockAddr.Size()); FD_ZERO(&r); FD_SET(sock,&r); timeout.tv_sec = 5; timeout.tv_usec =0; ret = select(0,0,&r,0,&timeout); if ( ret <= 0 ) { closesocket(sock); return false; } 以下是对select函数的解释: int select ( int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout ); 第一个参数nfds沒有用,仅仅为与伯克利Socket兼容而提供。 readfds指定一個Socket数组(应该是一个,但这里主要是表现为一个Socket数组),select检查该数组中的所有Socket。如果成功返回,则readfds中存放的是符合可读性条件的数组成员(如缓冲区中有可读的数据)。writefds指定一个Socket数组,select检查该数组中的所有Socket。如果成功返回,则writefds中存放的是符合可写性条件的数组成员(如连接成功)。 exceptfds指定一个Socket数组,select检查该数组中的所有Socket。如果成功返回,则cxceptfds中存放的是符合有异常条件的数组成员(如连接接失败)。 timeout指定select执行的最长时间,如果在timeout限定的时间内,readfdswritefdsexceptfds中指定的Socket沒有一个符合要求,就返回0 如果对 Connect 进行非阻塞调用,则可读意味着已经成功连接,连接不成功则不可读。所以通过这样的设定,我们就能够实现对connect连接时间的修改。但是,应该注意,这样的设置并不能保证在限定时间内连接不上就说明网络不通。比如我们设的时间是5秒,但是由于种种原因,可能第6秒就能连接上,但是函数在5秒后就返回了。
     
    非阻塞recvfrom的设置
     int iMode = 1; //0:阻塞
     ioctlsocket(socketc,FIONBIO, (u_long FAR*) &iMode);//非阻塞设置
     
     rs=recvfrom(socketc,rbuf,sizeof(rbuf),0,(SOCKADDR*)&addr,&len);
     
    int ioctlsocket (
     SOCKET s,        
     long cmd,        
     u_long FAR* argp 
    );
     
     
    s
    [in] A descriptor identifying a socket.
    cmd
    [in] The command to perform on the socket s.
    argp
  • 相关阅读:
    PNG文件格式具体解释
    opencv2对读书笔记——使用均值漂移算法查找物体
    Jackson的Json转换
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 单词接龙
  • 原文地址:https://www.cnblogs.com/zahxz/p/2880059.html
Copyright © 2011-2022 走看看