socket通信中send()和recv()的行为

Posted

技术标签:

【中文标题】socket通信中send()和recv()的行为【英文标题】:The behavior of send() and recv() in socket communication 【发布时间】:2011-02-04 19:48:22 【问题描述】:

以下是设置:

服务器客户端
 | |
接受连接
 | |
 v |
发送 msg1-> |
 | |
 v v
接收  recv
 | |
 v v
               关闭

这是我的问题: 1.客户端实际上在关闭之前就收到了msg1,为什么会这样? 2.发送msg2正常返回。既然client收到msg1就关闭了,为什么send msg2成功了?

附:我正在为 TCP 使用流套接字。

【问题讨论】:

你在使用数据报套接字吗?如果是这样,发件人根本不知道是否在任何地方收到过任何发送。 【参考方案1】:

    recv 函数将获取接收缓冲区中的下一个内容。在客户端的情况下,如果套接字是一个数据报套接字,接下来是msg1。如果它是一个流套接字,则不维护消息边界,因此如果 msg2 已经到达并且在那里,recv 可以包含来自 msg1msg2 的数据在 recv 缓冲区中有两个空间。

    send 不等待对方发送recv 消息,它只是将其添加到发送队列中。那时它不知道客户端是否会在读取连接之前关闭它。如果您需要知道应该让客户端发送响应以确认消息。

【讨论】:

为什么在调用recv()之前收到了数据?我认为在 send() 完成之前不会调用 recv(),但是在 send() 完成之前由服务器发送 msg1。 TCP 栈负责发送/接收数据。您不必为操作系统调用 recv() 来接收数据 - 至少直到操作系统的内部缓冲区已满。请记住,TCP 也是基于流的,而不是面向消息的 - 一次 send() 调用可能需要多次 recv() 调用才能接收,反之亦然。 当数据从网络到达时,操作系统会对其进行缓冲,直到您的应用程序调用recv()。到那时可能已经有几个数据包到达,您的应用程序可以通过一次调用recv() 一次获取所有数据。如果您不调用recv(),它将继续缓冲数据,直到接收窗口已满。然后您必须致电recv() 为更多数据腾出空间。【参考方案2】:

建立连接后,操作系统会管理进出系统的数据包,recv() 调用只是读取数据包缓冲区,而 send() 调用只是对数据包进行排队。

【讨论】:

以上是关于socket通信中send()和recv()的行为的主要内容,如果未能解决你的问题,请参考以下文章

ZMQ:socket_send/recv 阻塞

socket 的recv函数返回0应该怎样处理

socket编程·send和recv

read() 和 recv() 以及 send() 和 write() 之间有啥区别?

socket send 和 recv 中 FLAG 的含义

socket通信