通过 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 字节的块并不意味着它将以这种方式接收。如果您填充管道的速度足够快以获得零窗口条件(即,接收缓冲区或发送缓冲区中没有更多空间),那么接收器代码很可能在某个时候能够读取很远一次超过你的“数据包”的大小。

如果您没有特别请求非阻塞套接字,那么sendrecv 都将阻塞为零窗口/窗口满状态而不是返回错误。

如果您想粘贴接收方代码,我们可以看一下,但根据您的描述,您的第 9344 次读取听起来很可能实际上比您的数据包大小获得更多的字节。你检查从recv返回的值吗?

【讨论】:

【参考方案3】:

您的网络中的iperf 是否也无法发送此数量的这种大小的数据包?如果没有,请检查他们如何发送这么多数据。

【讨论】:

【参考方案4】:

嗯,根据我在Wikipedia 上读到的内容,这可能是某种缓冲区溢出(接收器报告零接收窗口)。不过只是猜测。

【讨论】:

以上是关于通过 posix 套接字发送文件时的零窗口的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 Java 中的套接字发送大文件

通过套接字编程发送图像文件(jpeg、png)的提示/示例?

通过套接字(python)发送包含文件的字典

使用 C 中的套接字通过 TCP 发送音频文件

通过 Linux 套接字发送文件描述符

通过 HTTPS 发送大文件时的性能影响 [重复]