使用 C TCP 套接字,“发送”可以返回零吗?

Posted

技术标签:

【中文标题】使用 C TCP 套接字,“发送”可以返回零吗?【英文标题】:With C TCP sockets, can 'send' return zero? 【发布时间】:2011-03-06 03:32:43 【问题描述】:

C send 函数在使用 TCP 套接字时是否有可能返回零?手册页只是说它将返回发送的字节数,但我不确定它是否会在无法发送任何数据时返回 -1。

【问题讨论】:

【参考方案1】:

我现在确实在AF_UNIX 类型的套接字上观察到来自send(2) 的零返回。

是的,这是由于 size 字段的值为零。

所以,JFYI。

【讨论】:

【参考方案2】:

BSD man 页面指出:

如果套接字上没有可用的消息空间来保存要传输的消息,则 send() 通常会阻塞,除非套接字已被置于非阻塞 I/O 模式。

Posix 规范更进一步,指出在阻塞模式下所有数据都会被传输,除非发生中断。

在这两种情况下都不能返回零,除非提供的计数为零。

【讨论】:

【参考方案3】:

我很确定,虽然内存在时间的迷雾中很深,但我之前已经看到它返回零,在另一端跟不上的大量数据传输的情况下。

从内存中,在这种情况下,远程 TCP 堆栈缓冲区已填满,堆栈已通知本地端它要延迟,直到一些空间被清除并且本地缓冲区也已填满。

此时,从技术上讲,这不是错误(因此没有返回 -1),但本地堆栈不能接受任何数据。

我不完全确定现在是这种情况,因为当前的 Posix 标准似乎表明它只会在这种情况下阻塞(或者如果它设置为非阻塞则失败)。

但是,我怀疑这是一个有争议的问题。您确实有可能返回少于的字节数,而不是您请求发送的字节数,因此您应该有适当的代码来处理它。

而且,由于处理“比您要求的少一个”与处理“零字节”的逻辑几乎相同,因此您不妨假设它可以返回零。

【讨论】:

应该如何处理?我的程序应该继续尝试发送,还是应该失败? 您应该继续尝试发送,因为这不是错误情况。如果它没有恢复,那么你最终会得到一个错误。这就是你应该指出失败的地方。您可能要考虑的一件事是在重试之前在零返回码之后引入延迟。这会给临时问题更多的时间来解决问题。为此,您可以采取多种策略。 这不是只有在非阻塞的情况下吗? @paxdiablo:我不认为你的解释是正确的。如果套接字处于阻塞模式,并且接收器报告其接收缓冲区已满,则 send() 会简单地阻塞,直到它可以再次发送数据(或发生致命错误/超时)。如果套接字改为非阻塞模式,则它立即返回 -1 和 EWOULDBLOCK 错误代码。以我的经验,返回值为 0 总是意味着有 0 个字节被传递给了 send(),或者对方已经优雅地关闭了套接字(或者至少调用了 shutdown(0))。 @RemyLebeau 我同意。 send() 的行为不依赖于实现,与此答案中断言的相反。几十年前,它由 BSD 和 Posix 定义。但是,您对“对方已优雅关闭”的评论是不正确的。如果您继续发送,这将导致 ECONNRESET,而不是返回代码为零。【参考方案4】:

这个问题的答案很可能取决于实现,因此会因操作系统而异。

当您请求传输 0 字节时,预期为 0 的一种情况。

【讨论】:

实际上,它不依赖于实现。当接收 TCP 的接收窗口已满或发送 TCP 的发送缓冲区已满时,您很可能要求发送某些内容。在这种情况下,send() 很容易返回零。 在这些情况下,send() 将阻塞直到空间可用(然后返回大于零的某个值),或者如果套接字处于非阻塞模式,它将返回 -1/EWOULDBLOCK 【参考方案5】:

嗯,总是有这样的情况,你传入零作为要发送的字节数......在这种情况下,“返回发送的字节数”表示它应该返回零字节。

无论如何,最好还是正确处理返回零的情况;它不会伤害,它可能会有所帮助。

【讨论】:

以上是关于使用 C TCP 套接字,“发送”可以返回零吗?的主要内容,如果未能解决你的问题,请参考以下文章

C - 填充 TCP 套接字发送缓冲区

Python中的TCP发送错误-套接字的协议类型错误

基于 C++ TCP 的服务器套接字需要时间才能返回 10054 错误。它不会立即返回

C TCP套接字,带有文件发送的回显服务器,发送文件后挂断

使用 Qt 通过 TCP 套接字部分发送 xml 消息

Linux:在 TCP 套接字上发送整个消息或不发送任何消息