http://blog.csdn.net/skiing_886/article/details/8044186

关于IOCP中是否可以对同一socket连续投递的疑问已经很久了,主要的疑问在wsaSend是否可以保证数据的完整发送,是否会出现部分发送成功的情况?

网上大多数的建议都是WSASEND采用线性模式,即建立一个发送缓冲,当上一次send完成之后,再进行下一次的投递。那么WSASEND什么情况下会出现部分发送呢?

在MSDN中IOCP的列子是对得到的发送的字节值进行了判断的,而在wsaSend函数的描述中也有这样一句:Note  The successful completion of a WSASend does not indicate that the data was successfully delivered.

我首先想到的是当发送缓冲区不足的时候,会不会造成wsaSend部分发送返回。做了个实验,连续发送10M的数据(肯定大于缓冲区了)。第一次直接返回成功(对端并未进行Recv),第二次返回IO_PENDING.看来不是这样的。查了《windows 网络编程技术》其中有这样一段话:

When an application makes a send call, if there is sufficient buffer space, the data is copied into the socket's send buffers, the call completes immediately with success, and the completion is posted. On the other hand, if the socket's send buffer is full, then the application's send buffer is locked and the send call fails withWSA_IO_PENDING. After the data in the send buffer is processed (for example, handed down to TCP for processing), then Winsock will process the locked buffer directly. That is, the data is handed directly to TCP from the application's buffer and the socket's send buffer is completely bypassed。

当发送缓冲不足的时候,会内存锁定,我另一端调用recv,收到wsasend的完成信号时,发送的字节数=要发送的字节数,并没有部分发送。

下面是我网上找到的一片帖子忘了出自哪里了。

---------------------------------------------------------------------------------------------------------

对于WSASend使用,一直有些疑惑,虽然对开发影响不大,但是总是很别扭。

疑惑1:

按照MSDN的说法:
1)不必等待WSASend发送成功,可以连续调用WSASend发送数据。
2)可以给WSASend提供一个Buffer数组,一次发送多个不连续的缓冲区
3)使用WSASend发送成功后,提供的数据不保证能够被全部发送出去

这样是否存在这样的问题:
假如我连续投递了5个WSASend发送数据,如果第3个WSASend的数据没有完全发送出去,而第4个WSASend又被接受,岂不是导致错误,因为系统无法得知我的第4个WSASend何时投递。

如果第3个发送数据的第2个参数是一个Buffer数组,我为了发送剩余数据,岂不要检查到底发送了几个Buffer?

为了保险起见,我的项目中没有连续投递过WSASend,也没有使用过多Buffer的功能,而是老老实实地在WSASend发送成功后,检查数据是否发送完全,如果没有,继续发送剩余数据,直到一次数据全部发送出去后,才发送下一个数据包。

疑惑2:

数据发送成功的含义(WSASend调用返回STATUS_SUCCESS或完成例程被调用或完成例程被调用或在完成端口上dequeue了一个完成包),可能情况:

1)数据被提交到tdi Client(AFD),就认为数据发送成功了
2)数据被提交到到tdi Server(如TCP),加入tcp的发生队列,就认为数据被发送成功了
3)数据被提交到网卡的发送缓冲区,就认为数据发送成功了
4)数据被网卡发送出去,就认为发送成功了
5)数据被对方成功接收,收到确认,就表示发送成功了。
以上情况到底属于那一种呢?按照MSDN的说法,发送请求被传输层消费掉了,就认为发送成功了,不知大家是如何理解这句话。

对于以上两个疑问,网络上也是没有一个定论,看来要搞清楚以上两个问题,不深入windows源码是无解了。

先说说WSASend的调用过程吧(基于NT4源码),源码就不贴了,免得MS找麻烦:

WSASend->WSPSend->NtDeviceIoControlFile->AFDSend【Tdi Client】->TcpSendData【Tdi Server】->TdiSend->TcpSend->IPTransmit【Network Layer】->SendIPPacket->下面进入链路层,没有找到相关源码

NtDeviceIoControlFile:
将发送请求和完成例程被包装成IRP,发送给"device/afd"

AFDSend:
根据buffer数组生成MDL链
如果TDI不支持数据缓冲,这里要将数据缓冲下来
调用TdiBuildSend构造发送到tdi的发送请求IRP
将生成新的IRP发送到“device/tcp”
AFDSend要么将完整数据提交到Tdi,要么失败,这里不会导致发送部分数据

TcpSendData:
构造TdiRequest并调用TdiSend处理,没有数据缓冲

TdiSend:
构造TcpRequest,并将该Request挂入TCB(TCP的传输控制块)的发送队列
调用TCPSend进一步处理
返回TDI_PENDING
该部分也不会导致数据不完整发送。

TCPSend:
检查TCB中发送队列的情况,决定是否启动一次发送,如果不满足发送条件,就返回了
如果符合发送条件,就构造TCP数据包,发送数据,这个过程比较复杂,多为TCP协议的细节处理
可以看出,WSASend一般到TCPSend的开始部分就返回了,TCPSend本身无返回值,是由TdiSend调用完后就直接返回了Pending。

从源代码上看,除了发送的数据的字节为0,否则WSASend是不会返回STATUS_SUCCESS,不出错的话,一定是返回Pending状态

但是应用层何时收到发送成功通知呢?
我们知道,完成例程指针被存在了最上层的那个Irp里了,在执行IoCompleteRequest的时候,完成例程会被调用,细节就不说了,检索源代码,有两个地方会导致IoCompleteRequest被最终调用,一个是链路层调用IP层的完成例程的时候,一层层调用下去,最终导致最上层的那个IRP的完成例程被调用,另一个是再处理TcpReceive的ACK的时候,也有可能完成掉一些发送请求。

结论:
纵观NT4源代码,没有发现WSASend发送部分数据的可能(也许有,我没看出来)
基于WSASend不会发送部分数据,WSASend的确可以重叠发送(按照投递顺序将发送请求挂入TCB的发送队列),不必串行,在一定程度上的确能够提高效率。
所谓发送完成,应该是链路层调用了上层的完成例程,但是链路层何时调用上层的完成例程,由于源代码缺乏,不得而知,请知情者赐教!
--------------------------------------------------------------------------------------

看来WSASend是在把请求放入TCB队列就返回了。Google过一些英文网站,得到类似的回答

Actually, a partial overlapped send guarantees all subsequently
  scheduled sends will completely fail (assuming a TCP socket).
  A partial overlapped send will never happen in practice, however,
  due to the implementation of the socket buffer (partial sends don't
  exist in Microsoft's WinSock implementations so far). There's an
  exception if you set the send buffer size to zero - then your overlapped
  buffers replace the socket buffer and the socket may break part way
  through an overlapped buffer.

貌似连续wsaSend是可行的。

再看MSDN 有这样一段话

For non-overlapped sockets, the last two parameters (lpOverlapped,lpCompletionRoutine) are ignored andWSASend adopts the same blocking semantics assend. Data is copied from the buffer(s) into the transport's buffer. If the socket is non-blocking and stream-oriented, and there is not sufficient space in the transport's buffer,WSASend will return with only part of the application's buffers having been consumed. Given the same buffer situation and a blocking socket,WSASend will block until all of the application buffer contents have been consumed.

之前的理解有误,这段话应该联合起来理解,对于未使用overlapped的socket,最后两个参数是被忽略的 这时候wsasend表现就和send一样,数据被拷贝到发送缓冲区,在这种情况下(wsasend像send) 如果是面向流的nonblockingmodel的套接字  并且发送缓冲区不足的情况下,wsasend返回拷贝到发送缓冲区的字节数,如果是blocking socket wsasend知道发送完毕才返回。(这个行为和send是一致的,也就是只有在这种情况下wsaSend才会部分发送)

什么是non-overlapped sockets?之前一直把non-overlapped sockets 当做blocking socket .

再看windows网络编程

Blocking sockets cause concern because any Winsock API call on a blocking socket can do just that—block for some period of time. Most Winsock applications follow a producer-consumer model in which the application reads (or writes) a specified number of bytes and performs some computation on that data.

Once a socket is placed in non-blocking mode, Winsock API calls that deal with sending and receiving data or connection management return immediately. In most cases, these calls fail with the error WSAEWOULDBLOCK, which means that the requested operation did not have time to complete during the call. For example, a call torecv returnsWSAEWOULDBLOCK if no data is pending in the system's input buffer. Often additional calls to the same function are required until it encounters a successful return code

No –Blocking socket是不同于non-overlapped socket

之前对于overlap的理解还是有些误区

现在的理解是 overlap是一种异步使用方式 与block no blocking 不是一个感念。

overlapIO不只是socket,还包括readfile等等同样iocp对应的也不只nonblockingsocket而是 overlapIO

Overlapped sockets merely means that you can use the sockets for overlapped IO. It doesn't mean that your socket is non-blocking.

完成端口和重叠IO的例子都没有指定socket必须是non-blocking socket.

non-blocking socket 是指不满足当前条件的情况下     返回,当满足当前需求,还是操作完成才返回,例如将发送缓冲区填满。

而overlap socket是只要当前情况不能立即执行完毕 便会返回pending 也就是说 在发送缓冲区填满前就已经返回了。

在我自己的测试程序中 我把发送和接受缓冲区大小都设置为了0 所以每次发送返回都是peding,系统锁定发送缓冲,当发送完成后得到完成通知。

所以重叠IO和完成IO 与block socket non blocking socket 是两码事 ,我接下来测试下用blocksocket 与non blockingsocket 在iocp上有什么影响 ,个人现在感觉应该是一样的。(经过测试 用blocking socket iocp仍可正常工作,单non-overlapped socket不行 默认的socket()创建出的是支持overlapped的)

现在的系统使用non-blocking socket必须使用overlap模式

没想到这篇文章写了一年之后才来更新 呵呵  写的比较乱 原

转载于:https://blog.51cto.com/6265510/1077763

IOCP中多次投递WSASend相关推荐

  1. IOCP中在WSASend以及WSARecv的时候出现WSA_IO_PENDING情况的说明

    应该是windows网络编程第二版里面提到过.现在整理一下. 1:在IOCP中投递WSASend返回WSA_IO_PENDING的时候,表示异步投递已经成功,但是稍后发送才会完成.这其中涉及到了三个缓 ...

  2. IOCP中的socket错误和资源释放处理方法

    前言:  错误处理和socket释放, 是IOCP编程中的一大难点. 本文试图就IOCP设计中经常遇到的这个难题展开论述并寻找其解决方案, 事实上, 文中所述的解决方式不仅仅适用于IOCP, 它同样适 ...

  3. iocp(完成端口)采用WSARecv WSASend处理数据,WSASend群发(广播)消息

    最近在耍iocp,也在网上看了不少例子,但却基本没看到使用WSASend群发的例子 最多只是使用WSASend将数据回传,而这个功能相对比较简单,只要学会使用WSARecv 回传则比较容易实现,而广播 ...

  4. windows套接字IOCP模型

    本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念,这些概念都是与基于IOCP的开发密切相关的,对开发人员来讲,又不得不给予足够重视的几个概念: 1) 基于IOCP实现 ...

  5. IOCP 浅析与实例

    这一年半来一直在做游戏项目逻辑层,学会了不少东西,觉得自己应该看看服务器底层的东西了,主要的东西就是网络模块,网络模块是沿用以前项目的,在 我们项目中被我们头改动过几次,现在还是比较稳定的.因为是Wi ...

  6. IOCP扩展方法AcceptEx, DisconnectEx, GetAcceptExSockaddr用法示例

    这篇文章记录了我刚接触IOCP模型时的理解,对于初学者,应该算不错的调试程序,仅有一个400多行代码的dpr文件,可以直接用WriteLn输出信息,前提是会用delphi建立Console Appli ...

  7. 异步通信之IOCP详解

    一. 概述 学习完网络基础,在写C/S应用程序时,大多童靴写服务器基本都没有用到io模型,基本都是采用"accept同步拥塞通讯和多线程方式"与客户端通讯.但当有成千上万客户端请求 ...

  8. 关于IOCP乱序的探讨

    关于IOCP的探讨 本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念,这些概念都是与基于IOCP的开发密切相关的,对开发人员来讲,又不得不给予足够重视的几个概念: 1 ...

  9. windows的IOCP(Input Output Completion Port,输入输出完成端口)

    windows的IOCP(Input Output Completion Port,输入输出完成端口) windows的IOCP(Input Output Completion Port,输入输出完成 ...

  10. 网络编程——IOCP

    参考 <TCP/IP网络编程> 尹圣雨 IOCP IOCP(Input Output Completion Port,输入输出完成端口)是性能最好的Windows平台I/O模型.Linux ...

最新文章

  1. 无序和有序列表的list-style-type 属性值
  2. php3.2手册中文版,Uploadify v3.2中文手册分享
  3. 【Android自定义View实战】之自定义评价打分控件RatingBar,可以自定义星星大小和间距...
  4. [CQOI2009]叶子的染色(树形dp)
  5. 软件测试基础:MantisBT的安装配置及使用——BUG管理工具
  6. [建议]添加模板功能
  7. MFC开发IM-第十二篇、MFC改变static text背景色为透明
  8. 使用git clone命令下载代码时报错出现 remote: Not Found fatal: repository 'http://xxx/xxx.git/' not found
  9. linux mysql 查询慢_linux – MySQL非常简单的SELECT查询速度极慢
  10. Silverlight 2.0 RTW 正式版发布(附下载地址)
  11. 浅谈Event Loop
  12. 【安卓项目】期末大作业——“记账宝”APP开发案例
  13. 运行c程序的步骤及方法
  14. win10桌面计算机图标隐藏,win10系统隐藏桌面单个图标的恢复方法
  15. 如何让必应bing收录我的网站
  16. 深度学习框架Caffe学习系列(2):Ristretto 量化 cifar_small 实验记录
  17. 基于java的高校实验室排课系统
  18. Python实现一个全国各高校查询系统
  19. MyTT工作(一)ListView使用
  20. 读书笔记:《与爱因斯坦月球漫步》

热门文章

  1. python学习浅谈(python2.x以及python3.x的区别、IDE)
  2. 软件测试常见断言,5.6 postman 常用的断言
  3. python防反编译_linux python如何反编译成源码
  4. 蓝桥杯2015年第六届C/C++省赛C组第二题-立方尾不变
  5. eclipse没有server选项怎么解决
  6. Android调试wifi使用wpa_supplicant和wpa_cli总结
  7. 进阶篇:3.4.1)机械加工件-不同制造工艺详解和对应设备
  8. Opencv的KeyPoint和DMatch数据结构
  9. 《Spring》(十一) ---- 基于注解的依赖注入
  10. HCIE-RS-TAC-01-AR29的loopback0无法访问AR28的loopback