使用 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 套接字,“发送”可以返回零吗?的主要内容,如果未能解决你的问题,请参考以下文章