WSASend的新发现,与大家共享,也期望有人提出不同的看法!

ProgrameMan 2006-12-05 02:38:07
最近由于项目的需要,我研究了一下重叠IO for 完成例程,发现网上比较流行的一些说法存在问题:

网上的说法:
1. WSASend 投递的数据缓冲区,如果系统的发送缓冲区不足(包含被设定为0的情况),系统会锁定用户提供的缓冲区(直到完成例程返回,在此期间用户提供的缓冲区不允许被修改)
2. 当完成例程返回的时候说明数据发送完毕!

我的说法:

以上两点经实际测试均是错误的。
对于第一点,我做了一个测试程序,发送的过程是这样的
1. 客户端连接到服务器。
2. 客户端向服务器发送一个字符串,内容为 "hello"
3. 设置用于发送数据给客户端的套接字的缓冲区为 0(不设置的结果和设置的结果一样)
4. 服务器接收到客户端发送的"hello"后发送一个大小为 10240000 字节的数据(在栈上的变量)给客户端,内容全部为 "1", 然后我调用 WSASend 发送这个字符串
5. WSASend返回 WSA_IO_PENDING 后我立即修改发送数据中第 4098 位置的一个字符为 "2"。
6. 客户端循环接收数据直到长度为 10240000字节。

结果: 有时客户端收到数据的第 4098 位置不为字符 "1" 为修改后的字符 "2"

结论: 这说明 WSASend 在系统发送缓冲区不足的情况下会锁定内存的结论是错误的,不然用户不会接受到修改后的数据。

对于第二点:
同样是哪个测试程序只是将发送的数据改成了3个字节,我在服务器调用WSASend的位置设置了端点,然后当服务器程序执行到这里的时候我拔掉客户端的网线,然后继续执行服务器程序。

结果: 此时完成例程依旧被调用,而且发送的字节数显示为 3 且用GetLastError 返回的错误码为 0。

结论: 这说明 WSASend 调用后完成例程返回成功不代表数据发送成功,而仅仅代表数据被投递到系统的发送缓冲区而已。

***********************************************************************

这就是我网上比较流行的两种说明的测试结果,个人认为应该比较说明问题,如果哪位大人认为不对,可以在此讨论一下。

期待大家的批评指正。










...全文
666 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
ProgrameMan 2006-12-12
  • 打赏
  • 举报
回复
我说错了,不是发送完成,而是提交到缓冲区
ProgrameMan 2006-12-12
  • 打赏
  • 举报
回复
系统会按照顺序发送还是?这时候两次数据的发送顺序是???
********************************************************

我认为系统会保障发送的次序,也就是说除非你第一次提交的数据全部发送完成,然后系统才会发送你第二次提交的数据,换句话说也就是如果第一次发送没有完成(包括数据发送不完整的情况),那么第二次的发送肯定不会被处理。
fengge8ylf 2006-12-12
  • 打赏
  • 举报
回复
有关完成端口的疑问比较多 主要不清楚底层是怎么实现的
toxyboy 2006-12-12
  • 打赏
  • 举报
回复
都周二了,人呢?:)
借你的人气,在咨询个问题:
在一个连接中调用两次WSASend,一次发送了40960字节的0到客户端,一次是1,服务器每次GetQue返回的都是完整发送,所以客户端也没有乱序接收,没有模拟出ERROR_IO_PENDING情况。现在对tcp的乱序很迷惑ing。
我的想法;如果第一次投递到套接字s上的数据大于了数据缓冲区,那么操作系统锁定该区域,发送(有可能继续针对该ol投递发送),这时候如果用户重新投递一个新的WSASend,如果这次投递数据正好可以copy到缓冲区,则,系统会按照顺序发送还是?这时候两次数据的发送顺序是???
期待高人。。。
ProgrameMan 2006-12-11
  • 打赏
  • 举报
回复
下周1结贴
ProgrameMan 2006-12-09
  • 打赏
  • 举报
回复
回复人:ProgrameMan(我要学汇编) ( 五级(中级)) 信誉:89 2006-12-5 19:58:22 得分:0
?

to fengge8ylf(寻P2P工作或项目)

**********************************************

send 如果是同步的,当send返回时,应该是指到了接收端的接收缓冲区吧


***********************************************************************************

更正: fengge8ylf 的说法是正确的,而我的说法是错误的,这个结论是经过测试的。
浮云一梦 2006-12-08
  • 打赏
  • 举报
回复
我也比较同意楼主的意见。
更多关注中...
ProgrameMan 2006-12-07
  • 打赏
  • 举报
回复
to toxyboy(长的比较无奈)

你看看的第一个例子,结论和你(以前我也是这么认为)说的不同的。
toxyboy 2006-12-07
  • 打赏
  • 举报
回复
just a discuss .. Obtain knowledge is aim!!!
toxyboy 2006-12-07
  • 打赏
  • 举报
回复
我的理解:
这里的锁定就是对应用来说不能修改的意思.
等数据发送缓冲区结束以后,系统会找到这块锁定的区域来发送数据,是不是理解为系统会记录应用层的数据,等到能发送的时候找到这块数据来发送.
如果非要操作出现的将是不合理的操作结果或者异常..
ProgrameMan 2006-12-07
  • 打赏
  • 举报
回复
楼上的,then the application's send buffer is locked... 锁定和未锁定有什么不同?
toxyboy 2006-12-07
  • 打赏
  • 举报
回复
Let's look at how the system handles a typical send call when the send buffer size is non-zero. 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 with WSA_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.

摘之<<windows 网络编程2>>
对上面的说明还有异议的吗?呵呵,继续讨论.
toxyboy 2006-12-07
  • 打赏
  • 举报
回复
写错了,意外的断开。。
csdn不好,不能编辑自己发的言。
benjiam 2006-12-07
  • 打赏
  • 举报
回复
心跳测试

我一直不太清楚。 你们指的是外带数据实现吗?
benjiam 2006-12-07
  • 打赏
  • 举报
回复
猜想:

GetQueuedCompletionStatus

if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)

PerHandleData 结构扩展一下里面加入这个这个PerHandleData 相关操作是 接收还是发送 就可以知道了。

toxyboy 2006-12-07
  • 打赏
  • 举报
回复
一般是用心跳测试的。。这种以外的端口很难用程序的方法捕获完全。
benjiam 2006-12-07
  • 打赏
  • 举报
回复
我的理解所谓的判断对方客户端崩溃的方法: 再加一次读操作。

其实就是在 RST到了以后 读socket 状态。因为socket 状态已经是对方崩溃了。 所以应该能很快知道。前提是对方的ip 栈工作正常。 但对方当机的情况还是无法知道。


所有猜测只是源于 对tcp/ip 卷一的理解。有错请指出

toxyboy 2006-12-07
  • 打赏
  • 举报
回复
问个问题:如果服务器在回送客户端一个很大的buffer,这个时候,程序设置的标志是IoWrite,可正好客户端发送了一份数据过来了。那么这个时候,GetQueuedCompletionStatus捕获到的是写返回还是客户端发送的返回。。。怎么辨别???
benjiam 2006-12-07
  • 打赏
  • 举报
回复
这说明 WSASend 调用后完成例程返回成功不代表数据发送成功,而仅仅代表数据被投递到系统的发送缓冲区而已。

这个东西 我的理解是这样的。

ip 栈发送数据的过程。

1 app 将数据 压入 tcp 栈 ip栈
2 将数据发向网络
3 对方ip 栈 tcp 栈接受到数据 去除校验 重传等问题 获取数据
4 对方ip 栈发回 ack 包
5 本地ip 栈收到了 相应ack包

send 成功只能是 1 成功后的返回
而不是5 的返回

对方ip栈崩溃的话 (当机)。 要75秒以后 这边的ip 栈才能知道
对方 ip栈正常,但服务停止的话, 对方会发回相应的RST (tcp) 那么这边的ip栈只要
等待RST包在网上的时间和本地ip栈工作的时间就能知道了。

我想知道 如何设置本地的socket 当对方的ack 包在30秒以内还没有回影。我们就认为对方已经吊线了。(排除修改注册表的办法)


ProgrameMan 2006-12-07
  • 打赏
  • 举报
回复
呵呵 楼上的没认真看我的例子
加载更多回复(16)

18,356

社区成员

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

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