打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
非阻塞模式

5.1.1 非阻塞模式

169人阅读 评论(0) 收藏 举报

  把套接字设置为非阻塞模式,即通知系统内核:在调用Windows Sockets API时,不要让线程睡眠,而应该让函数立即返回。在返回时,该函数返回一个错误代码。图所示,一个非阻塞模式套接字多次调用recv()函数的过程。前三次调用recv()函数时,内核数据还没有准备好。因此,该函数立即返回WSAEWOULDBLOCK错误代码。第四次调用recv()函数时,数据已经准备好,被复制到应用程序的缓冲区中,recv()函数返回成功指示,应用程序开始处理数据。

4274人阅读 评论(0) 收藏 举报

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

SOCKET s; //套接字

unsigned long ul = 1; //设置套接字选项

int nRet; //返回值

s = socket(AF_INET, SOCK_STREAM, 0); //创建套接字

nRet = ioctlsocket(s, FIONBIO, (unsigned long*)&ul); //设置套接字非阻塞模式

if (nRet == SOCKET_ERROR)

{

//设置套接字非阻塞模式,失败处理

}

套接字设置为非阻塞模式后,在调用Windows Sockets API函数时,调用函数会立即返回。大多数情况下,这些函数调用都会调用“失败”,并返回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有时间完成。通常,应用程序需要重复调用该函数,直到获得成功返回代码。下面程序清单示例了一个在非阻塞套接字上反复调用recv()函数,直到收到1024个字节的数据。

#define NUM_REQUIRED 1024 //需要读入数据的大小

#define MAX_SIZE 2048 //输入缓冲区的大小

TCHAR buff[MAX_SIZE]; //输入缓冲区

bool close; //对方关闭了连接

SOCKET sock; //Windows sockets

void ReadData(void)

{

int nTotal = 0; //已经读入缓冲区字节数

int nRead = 0; //在调用recv时实际读入字节数

int nLeft = 0; //剩下数据的字节数

int nBytes = 0; //当前已读数据在缓冲区的位置

nLeft = NUM_REQUIRED;

while (nTotal != NUM_REQUIRED)//已经读入缓冲区的字节数不等于需要读入的大小时

{

nRead = recv(sock, &buff[MAX_SIZE - nBytes], nLeft, 0); //接收数据

if(SOCKET_ERROR == nRead) //读操作失败

{

int err = WSAGetLastError();

if(WSAEWOULDBLOCK == err) //接收数据缓冲区不可用

{

continue; //接着读取数据

}else if(WSAETIMEDOUT == err || WSAENETDOWN == err) //连接已经断开

{

close = TRUE; //函数退出

break;

}

}

if( 0 == nRead) //客户端关闭了连接

{

close = TRUE; //函数退出

break;

}

nTotal += nRead;

nLeft -= nRead;

nBytes += nRead;

}

return;

}

在该程序中,通过调用WSAGetLastError()函数获得recv()函数返回的错误代码。当返回WSAEWOULDBLOCK错误时,说明此时套接字的缓冲区还没有准备好的数据。需要继续调用该函数。

在该程序中,还对recv()函数返回的其他错误代码进行处理。WSAETIMEDOUTWSAENETDOWN错误说明,此时由于网络系统的原因与对方的连接已经断开了。当函数返回0时,说明对方关闭了连接。在程序中通过设置close布尔变量值为TRUE,表明与对方的连接已经断开。调用break语句跳出while循环体,函数退出。在开发中,应该根据具体情况对函数返回的错误值进行具体处理。

不同的Windows Sockets API函数,在调用失败时返回的WSAEWOULDBLOCK错误代码具有不同的含义。表对几个Windows Sockets API函数返回WSAEWOULDBLOCK错误的含义进行了总结。

WSAEWOULDBLOCK的含义

函数名

说明

accept()WSAAcept()

应用程序没有收到连接请求

recv()WSARecv()recvfrom()WSARecvfrom()

接收缓冲区没有收到数据

send()WSASend()sendfrom()WSASendfrom()

发送缓冲区此时不可用

connect()WSAConnect()

连接未能立即完成

closescoket()

通常情况下意味着应用程序使用SO_LINGER选项并且设置了一个非零的超时值,调用了setsocketopt()函数

需要说明的是并非所有的Windows Sockets API在非阻塞模式下调用,都会返回WSAEWOULDBLOCK错误。例如,以非阻塞模式的套接字为参数调用bind()函数时,就不会返回该错误代码。当然,在调用WSAStartup()函数时更不会返回该错误代码,因为该函数是应用程序第一调用的函数,当然不会返回这样的错误代码。

要将套接字设置为非阻塞模式,除了使用ioctlsocket()函数之外,还可以使用WSAAsyncselect()WSAEventselect()函数。当调用该函数时,套接字会自动地设置为非阻塞方式。在后续章节中,讲解该函数的使用方法。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Socket 阻塞与非阻塞模式
socket阻塞与非阻塞,同步与异步、I/O模型
socket阻塞和非阻塞
Linux下串口通信详解(下)读写串口及关闭串口
MSG_WAITALL
Windows Sockets API实现网络异步通讯 | VC | 软件 | 天极Yes...
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服