【问题标题】:Will read (socket) block until the buffer is full?读取(套接字)是否会阻塞,直到缓冲区已满?
【发布时间】:2015-10-14 10:49:34
【问题描述】:

我编写了一个简单的 C 套接字程序,它向服务器发送一个 INIT 包以指示准备文本传输。服务器当时不会发回任何数据。 发送 INIT 包后,客户端发送一个 GET 包并等待来自服务器的数据块。 所以每次服务端收到一个 GET 包,它都会向客户端发送一大块数据。

到目前为止一切顺利。缓冲区大小为 512 字节,一个块为 100 字节加上一点开销大。

但是我的问题是客户端没有收到第二条消息。

所以我的猜测是 read() 将 blpck 直到缓冲区已满。这是正确的还是可能是什么原因?

【问题讨论】:

  • 不,read() 会读取所有内容。它只会在阻塞模式下阻塞,当没有数据并且没有其他事件挂起时。
  • 谢谢。那么可能是什么问题?会不会是第二条消息发送得太快了?
  • 没有。即使它是在客户端发送数据之前发送的,您也可以读取它,因为这是流套接字的操作方式。可能是这样,服务器没有收到完整的请求,因此没有发送响应。例如,在 HTTP 协议中,服务器在读取所有请求标头 + 换行符之前不会开始回复。所以检查那部分。
  • 所以我必须添加一个特殊的字符,比如\n吗?我没有。
  • 如果使用 HTTP,请求的结尾是两个 '\n' 字符(形成一个空行)。我不建议您实现自己的 HTTP 堆栈。改用一些现有的库。 HTTP 协议有点繁琐,并且有很多细微差别。否则,请阅读w3.org/Protocols/rfc2616/rfc2616.txt

标签: c sockets


【解决方案1】:

这取决于。对于 TCP 套接字,read 可能会在缓冲区满之前返回,您可能需要循环接收才能获得完整的消息。对于 UDP 套接字,您读取的大小通常是单个数据包(数据报)的大小,然后read 可能会阻塞,直到它读取所有请求的数据。

【讨论】:

  • 好吧,它是一个 tcp 套接字,我忘了说。我没有设置任何套接字选项。那么缓冲区是否必须已满才能使 read() 继续?根据您的回答:不。但是为什么会发生这种情况?第二个包裹发送太快了吗?
  • @Ctwx 使用 TCP 时,套接字 API 不处理数据包。如果你想通过 TCP 发送你自己的消息,你需要一种方法来知道一个这样的消息在哪里开始和在哪里结束。您的 read() 调用可以读取您的 4 条消息,或者它可以读取 1/3 条消息 - 您需要处理这些。
【解决方案2】:

答案是否定的:tcp/ip 套接字上的read() 不会阻塞,直到缓冲区具有您请求的数据量。如果有任何数据可用,read() 将在所有情况下立即返回,即使您的套接字阻塞并且您请求的数据多于可用数据。

请记住,TCP/IP 是一种字节流协议,您必须将其视为字节流协议。接口没有义务在一个数据包中一起传输您的数据,只要它按照您在套接字中放置的顺序呈现给您。

【讨论】:

    【解决方案3】:

    答案是否定的,read不是阻塞调用,你可以参考以下几点来猜测错误

    您可以找到几个检查点:

    1. 找出第二次读取返回的内容。
    2. 在 recv 之前的 while 中每次都 memset 缓冲区
    3. 如果无法输出,请使用 fflush(stdout)。

    确保所有三个都存在。如果问题还没有解决,请在此处发布源代码

    【讨论】:

      猜你喜欢
      • 2020-12-05
      • 2010-12-20
      • 2012-08-25
      • 1970-01-01
      • 2012-09-25
      • 2012-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多