通过 posix 套接字发送文件时的零窗口
Posted
技术标签:
【中文标题】通过 posix 套接字发送文件时的零窗口【英文标题】:Zero Window when sending files through posix sockets 【发布时间】:2009-11-27 13:31:59 【问题描述】:我有一个问题 - 当我尝试通过 posix 套接字发送大量数据(无论是文件还是某些数据)时,有时我没有收到我期望的 - 我使用了 wireshark确定导致错误的原因,我发现,正是在我的应用程序中断时,双向发送的数据包标记为红色,表示“零窗口”或“窗口已满”。
结果是,应用层没有得到send()函数发送的一条数据。但它得到了下一部分......
我是不是做错了什么?
编辑:
假设我想发送 19232 条数据,每条 1024 字节 - 在某个随机点(或根本不发送)而不是第 9344 个数据包,我得到第 9345 个数据包。而且我没有实现任何重传协议,因为我认为 TCP 会为我完成。
【问题讨论】:
TCP 应该为你做这件事......你能复制/粘贴你的代码的一部分吗? 我曾尝试使用套接字在 4 个 FC8 x86 系统上发送/接收大文件(比如几个 GB,带有 FILE64 选项),一个作为服务器和 3 个客户端。虽然我使用应用程序级消息传递库 Effo NetMsg (effonetmsg.googlecode.com)。如果是 TCP,应用程序 send() 可以通过使用协议和发送/接收缓冲区控制来传输更大的数据包(意味着 > MTU)。所以系统应该没有问题。 【参考方案1】:零窗口/窗口已满表示 TCP 连接的一端无法接收更多数据,直到其客户端应用程序读取一些已接收到的数据。换句话说,是连接的一方告诉另一方“在我告诉你之前不要再发送任何数据”。
TCP 确实处理重传。您的问题很可能是:
-
接收端的应用程序读取数据的速度不够快。
这会导致接收 TCP 向发送 TCP 报告窗口已满。
这反过来会导致发送 TCP 端的
send()
返回 0
(未写入字节)或 -1
并将 errno
设置为 EWOULDBLOCK
。
您的发送应用程序没有检测到这种情况,并假设 send()
发送了您要求发送的所有数据。
这会导致数据丢失。您需要修复发送端,以便它处理 send()
失败,包括返回一个小于您要求它发送的字节数的值。如果套接字是非阻塞的,这意味着要等到select()
告诉你套接字是可写的,然后再重试。
【讨论】:
【参考方案2】:首先,TCP是字节流协议,不是基于包的协议。仅仅因为您发送了一个 1024 字节的块并不意味着它将以这种方式接收。如果您填充管道的速度足够快以获得零窗口条件(即,接收缓冲区或发送缓冲区中没有更多空间),那么接收器代码很可能在某个时候能够读取很远一次超过你的“数据包”的大小。
如果您没有特别请求非阻塞套接字,那么send
和recv
都将阻塞为零窗口/窗口满状态而不是返回错误。
如果您想粘贴接收方代码,我们可以看一下,但根据您的描述,您的第 9344 次读取听起来很可能实际上比您的数据包大小获得更多的字节。你检查从recv
返回的值吗?
【讨论】:
【参考方案3】:您的网络中的iperf 是否也无法发送此数量的这种大小的数据包?如果没有,请检查他们如何发送这么多数据。
【讨论】:
【参考方案4】:嗯,根据我在Wikipedia 上读到的内容,这可能是某种缓冲区溢出(接收器报告零接收窗口)。不过只是猜测。
【讨论】:
以上是关于通过 posix 套接字发送文件时的零窗口的主要内容,如果未能解决你的问题,请参考以下文章
C# 在Winform设计一个耗时较久的任务在后台执行时的状态提示窗口