关于 WSASend/WSARecv 和重叠IO的几个问题?

guolaikk 2012-05-01 05:31:57
书上:
[Quote= Overlapped I/O事件通知模型:]
重叠I/O的事件通知方法要求将Win32事件对象与WSAOVERLAPPED结构关联在一起。若使用一个WSAOVERLAPPED结构,发出像WSASend和WSARecv这样的I/O调用,它们会立即返回。
通常,这些I/O调用会以失败告终,返回SOCKET_ERROR 。
一个重叠请求操作最终完成之后,在事件通知方法中,Winsock会更改与一个WSAOVERLAPPED结构对应的一个事件对象的事件传信状态,将其从“未传信”变成“已传信”。发现一次重叠请求完成之后,接着需要调用WSAGetOverlappedResult(取得重叠结构)函数,判断该重叠调用到底是成功,还是失败。
……
重叠I / O编程步骤为:
1) 创建一个套接字,开始在指定的端口上监听连接请求。
2) 接受一个进入的连接请求。
3) 为接受的套接字新建一个WSAOVERLAPPED结构,并为该结构分配一个事件对象句柄。也将事件对象句柄分配给一个事件数组,以便稍后由WSAWaitForMultipleEvents函数使用。
4) 在套接字上投递一个异步WSARecv请求,指定参数为WSAOVERLAPPED结构。注意函数通常会以失败告终,返回SOCKET_ERROR错误状态WSA_IO_PENDING(I/O操作尚未完成)。
5) 使用步骤3 )的事件数组,调用WSAWaitForMultipleEvents函数,并等待与重叠调用关联在一起的事件进入“已传信”状态(即,等待那个事件的“触发”)。
6) WSAWaitForMultipleEvents函数完成后,针对事件数组,调用WSAResetEvent(重设事件)函数,复位事件对象,并对完成的重叠请求进行处理。
7) 使用WSAGetOverlappedResult函数,判断重叠调用的返回状态是什么。
8) 在套接字上投递另一个重叠WSARecv请求。
9) 重复步骤5 ) ~ 8 )。

[/Quote]

1. 立即返回,这个“立即” 是什么含义?
2. 这些I/O调用为什么会通常以失败告终?
3. 既然WSASend的返回值可以判断是否发送成功,那这里为什么还要用WSAWaitForMultipleEvents 这么麻烦 ?
4. 据说有发送了一半的情况?是这样吗? 如果有这种情况的话,这算是成功还是失败?接下来怎么办?
...全文
434 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
yangxiang1027 2012-05-24
  • 打赏
  • 举报
回复
1. wsarecv和wsasend在异步I/O模式下面,可以看成只是将一个socket和一个wsaoverlapped的结构体关联在一起,由这个wsaoverlapped的结构体变量负责通知程序何时完成I/O操作,具体由WSAWaitForMultipleEvents函数来判断。
2. 正因为以上的1中的原因,wsarecv和wsasend一般情况下并不做具体的I/O操作,所以程序立刻返回。如果返回的不是SOCKET_ERROR,则表明具体的I/O操作已经完成;如果返回值为SOCKET_ERROR,则还要看WSAGetLastError函数的返回值,如果为ERROR_IO_PENDING,则表示1中的关联操作完成,如果不是则表示关联失败要closesocket了。
3. 大数据量的数据发送,可能系统给socket分配的缓冲区不能一次投递完所有的数据,这是必须分批完成数据的发送,所以这种情况下WSASend函数一般都是直接返回,Output操作具体的完成时间由WSAWaitForMultipleEvents函数来找。
4. WSAGetOverlappedResult函数中第3个参数LPDWORD lpcbTransfer会指明实际的数据发送量,所有数据没有发送完之前,不会触发WSAOverlapped结构里面的成员变量hEvent事件,自然也不会通知程序数据Output操作完成。
ps:关键还是理解以上的第1点,通常的recv和send(或者recvfrom和sendto)函数为阻塞函数,也就是直到I/O操作具体完成才会返回,但是异步模式的WSARecv和WSASend函数则完全不同。
Eleven 2012-05-03
  • 打赏
  • 举报
回复
1. 立即返回,这个“立即” 是什么含义?
-------------
函数会返回,不会阻塞

2. 这些I/O调用为什么会通常以失败告终?
-----------------
IO操作会在之后完成,当前可能没开始。

3. 既然WSASend的返回值可以判断是否发送成功,那这里为什么还要用WSAWaitForMultipleEvents 这么麻烦 ?
--------
IO操作完成以后,与之相关的EVENT事件对象为signal状态,表示操作完成。

4. 据说有发送了一半的情况?是这样吗? 如果有这种情况的话,这算是成功还是失败?接下来怎么办?
---------------
BOOL WSAGetOverlappedResult(
SOCKET s,
LPWSAOVERLAPPED lpOverlapped,
LPDWORD lpcbTransfer,
BOOL fWait,
LPDWORD lpdwFlags
);
该函数的第三个参数lpcbTransfer表示当前实际IO操作发送或者接受的字节数。
louifox 2012-05-03
  • 打赏
  • 举报
回复
异步WSASend需考虑2种情况:
1、系统缓冲足够,直接把数据拷贝到系统缓冲,函数返回
2、系统缓冲不够,锁定用户缓冲,函数返回
应用程序得到的通知是要么IO失败,要么数据全部拷贝成功,不会出现部分拷贝的情况
fishion 2012-05-02
  • 打赏
  • 举报
回复
1.立即返回就是说函数不会阻塞,是异步的,在一般使用中,WSARecv会阻塞的
2.MSDN上的:Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError. The error code WSA_IO_PENDING indicates that the overlapped operation has been successfully initiated and that completion will be indicated at a later time
3.如果用了重叠IO方式的话, WSASend的返回值不再是表示发送成功与否。当然,你可以在使用WSASend的时候不指定第六个参数,那它的第四个参数就表示发送的数据数目。
4.如果有发送了一半的情况,可以根据WSAGetOverlappedResult的第三个参数判断,再发送剩下的
mabaoyes 2012-05-01
  • 打赏
  • 举报
回复
1.立即返回,是不等待执行完成,异步操作都是这样。
2.返回的时候也会检查,是否完成,一般都没有完成,因为函数返回很快。
3.通过事件来判断是否真正完成了。当然中途你可以主动询问是否完成。
4.有发送一半的情况,你可以继续发送,把发送区填满。

就好比你有个手下,你给他一个任务,叫他画100个园,你回去先喝杯茶,他这时肯定没有画完,过会你再来看他画出30个园,你又同他说再增加50个园,要求总共画150个;你回去打麻将了,这时肯定还没画完。最后他画完150个,给你打电话,说画完。如果他不主动汇报,你就得不停检查他是否完成。但你不必一直守在他身边,看他画完,你还可以去打牌喝茶,这就是检查完立即返回。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧