Socket非阻塞模式开发

来源:互联网 发布:淘宝图片空间网址 编辑:程序博客网 时间:2024/05/17 21:51

套接字的非阻塞模式是指套接字在执行操作时,调用的函数不管操作是否完成都会立即返回的工作模式。把套接字设置为非阻塞模式,就是告诉系统内核:在调用Windows Sockets API函数时,不要让线程睡眠,而应该让函数立即返回。在返回时,该函数返回一个错误码。

一个非阻塞模式的套接字多次调用recv()函数的过程如下:

前三次调用recv()时,内核数据还没有准备好。因此,该函数立即返回WSAWOULDBLOCK错误代码。第四次调用时,数据已经准备好,被复制到应用程序的缓冲区中,recv()函数返回成功提示,应用程序开始处理数据。

当使用socket()和WSASocket()函数创建套接字时,默认都是阻塞的。在创建套接字之后,通过调用ioctlsocket()函数,将套接字设置为非阻塞模式。函数第一个参数是套接字,第二个参数设置为FIONBIO,第三个参数设置为unsigned long类型的非零值。

例如,如下程序将套接字设置为非阻塞模式:

SOCKETs;               //套接字unsigned long ul=-1;  //套接字选项,非零值int ret;      //返回值s=socket(AF_INET,SOCK_STREAM,0);ret=ioctlsocket(s,FIONBIO,(unsigned long*)&ul);if(ret==SOCKET_ERROR){      cout<<“设置非阻塞失败”<<endl;}
套接字设置为阻塞模式后,在调用Windows Sockets API时,调用函数会立即返回,大多数情况下,会返回错误代码,使用WSAGetLastError()函数获取错误代码。当但会WSAEWOULDBLOCK错误代码时,说明请求的操作在调用期间没没有数据准备好,需要继续调用该函数。

例:在一个非阻塞套接字上反复调用recv()函数,直到收到1024字节数据。

#define NUM_REQUIRED 1024   //需要读入数据的大小#define MAX_SIZE  2048    //缓冲区的大小char buffer[MAX_SIZE];  bool close;        //结束标志SOCKET sock;void ReadData(){int nTotal=0;      //已经读入缓冲区子数int nRead=0;   //在调用recv时实际读入字节数int nLeft=0;       //剩下的字节数int nBytes=0;      //当前已读数据在缓冲区位置nLeft=NUM_REQUIRED;while(nTotal!=NUM_REQUIRED){nRead=recv(sock,&buffer[MAX_SIZE-nBytes],nLeft,0);    //接收数据if(SOCKET_ERROR==nRead){      //读操作失败int err=WSAGetLastError();if(err==WSAEWOULDBLOCK){         //数据没准备好continue;}else if(err==WSAETIMEDOUT||err==WSAENETDOWN){       //连接断开close=true;    //结束break;}}if(0==nRead){     //另一端关闭连接close=true;break;}nTotal+=nRead;nLeft-=nRead;nBytes+=nRead;}return ;}
不同的Windows Sockets API函数,在调用失败时返回的WSAEWOULDBLOCK错误代码的含义不同:

但是并非所有的Windows Sockets API函数在非阻塞模式下调用都会返回WSAEWOULDBLOCK错误代码,例如,调用bind时就不会返回错误代码。


非阻塞模式的优势和不足:

优势:在控制建立的多个链接,在数据的收发量不均、时间不定等方面比较有优势。

不足:在Windows Sockets API调用时,会经常返回WSAEWOULDBLOCK错误代码,所以需要不断调用这个函数,不断检查错误代码。