日期:2014-05-17  浏览次数:21122 次

Windows Socket 非阻塞模式开发

                                                                  非阻塞套接字      

     非阻塞模式是指:套接字在执行操作时,调用的函数不管操作是否完成都会立即返回的工作模式。

    非阻塞套接字在处理同时建立的多个连接等方面具有明显的优势。但是使用过程中有一定的难度。由于函数在操作没有完成后也仍然会返回,为了实现某些功能必须循环调用,直到完成功能为止。因此非阻塞模式会使程序效率非常低。

    把套接字设置为非阻塞模式,即告诉系统:在调用Windows socket API时,不让主调线程睡眠,而让函数立即返回。比如在调用recv函数时,即使此时接受缓冲区没有数据,也不会导致线程在recv处等待,recv函数会立即返回。如果没有调用成功函数会返回WSAEROULDBLOCK错误代码。为了接收到数据必须循环调用recv,这也是非阻塞与阻塞模式的主要区别。

    默认情况下,使用socket或是WSASocket函数创建的套接字都是阻塞的。在创建套接字之后可以调用ioctsocket函数将套接字设置为非阻塞模式。

SOCKET s;

unsigned long ul=1;

int ret;

s=socket(AF_INET,SOCK_STREAM,0);

ret=ioctlsocket(s,FIONBIO,(unsigned long *)&ul);//设置成非阻塞模式。

if(ret==SOCKET_ERROR)//设置失败。

{

}


    如果Windows socket api函数在返回时,却没有完成功能,它将返回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有完成。通常情况下应用程序需要重复调用此函数直到返回值标识为成功为止。


while(true)

{

   ret=recv(s,buff,num,0);

   if(ret==SOCKET_ERROR)

   {

      err=WSAGetLastError();

      if(err==WSAEWOULDBLOCK)

      {

        continue;

       }

      else if(err==WSAETIMEDOUT)//超时。

      {

       }

      else if(err==WSAENETDOWN)//连接断开。

       {

       }

      else//其他错误。

         break;

   }

   else

break;//接受成功。

}


 

    在上面的代码中,WSAGetLastError函数返回WSAEWOULDBLOCK错误码时,说明此时套接字缓冲区还没有数据。需要继续调用。除了WSAEWOULDBLOCK错误码之外,还有WSAETIMEDOUTWSAENETDOWN错误,这些错误说明由于网络原因,与对方已经断开了连接。

     不同的Windows socket api虽然都返回WSAEWOULDBLOCK但是它们所表示的错误原因却不尽相同:

    对于acceptWSAAccept