【问题标题】:How to receive more than 40Kb in C++ socket using read()如何使用 read() 在 C++ 套接字中接收超过 40Kb
【发布时间】:2015-02-12 08:06:25
【问题描述】:

我正在使用 C++ 在 Linux 中开发客户端-服务器应用程序 (TCP)。此应用程序负责测试网络性能。 客户端和服务器之间只建立一次连接,然后通过自定义协议使用write()/read()发送/接收数据。

当数据超过 40Kb 时,我只收到一次数据的一部分。 (即我收到大约 48KB)

请找出代码的相关部分:

while (1) {
        servMtx.lock();
        ...
        serv_bytes = (byte *) malloc(size_bytes);
        n = read(newsockfd, serv_bytes,size_bytes);
        if (n != (int)size_bytes ) {
            std::cerr << "No enough data available for msg. Received just: " << n << std::endl;
            continue;
        }
        receivedBytes += n + size_header_bytes + sizeof(ssize_t);
        ....
}

我使用以下方法将内核缓冲区大小增加到 1MB:

int buffsize = 1024*1024;
setsockopt(newsockfd, SOL_SOCKET, SO_RCVBUF, &buffsize, sizeof(buffsize)); 

也修改了 sysctl 变量:

sysctl -w net.core.rmem_max=8388608; sysctl -w net.core.wmem_max=8388608;

正如How to recive more than 65000 bytes in C++ socket using recv() 中提到的,但没有任何改变。另外,我尝试更改包装大小无济于事。

【问题讨论】:

  • 您的代码错误。 n &lt; size_bytes 不是 n &gt; 0 时的错误情况,这是一种非常常见的情况。
  • 如您所知,read() 要么处理(并等待)'size_bytes'(即 n == (int)size_bytes),要么返回错误。
  • 顺便说一句,数据发送正确没有任何问题。而且我总是收到相同的确切字节数:/
  • @Mohamad-JaafarNehme 这完全不正确,它是您的问题的原因。它阻塞直到至少一个字节到达,或者流结束或错误。请参阅 man 页面。你必须循环。这是一个字节流协议,而不是一个消息协议。
  • @Mohamad-JaafarNehme:因为你运气不好。

标签: c++ sockets buffer


【解决方案1】:

您应该将readrecv 分成几个块(一般情况下;如果运气不好,“几个”会变成“一个”)。所以你需要管理你的缓冲并保持(和使用)接收到的字节数。

所以在某些时候,你会编码

int nbrecv = recv(s, buffer + off, bufsize, 0);
if (nbrec>0) { off += nbrecv; bufsize -= nbrecv; }

您可能应该在您的event loop 中这样做(通常在poll(2)... 附近)。 nbrec 确实比 bufsize 少很多,您应该处理这种常见情况。

TCP 不保证您将获得同一个recv 中的所有字节!它可能取决于外部因素(路由、网络硬件……);它是一种面向流的协议,而不是消息包协议。如果您的应用程序需要 messages,它应该根据内容将输入和输入块缓冲到消息中。查看HTTPSMTP:它们的消息具有由标头信息(HTTP 中的Content-Length:)或结束约定(SMTP 中的单个.)给出的明确定义的边界。

请仔细阅读read(2)recv(2)socket(7)tcp(7)、部分sockets tutorialAdvanced Linux Programming

【讨论】:

  • @Mohamad-JaafarNehme 您的评论没有意义。删除旧数据他也没说什么,TCP里也没有消息这种东西。
  • @Mohamad-JaafarNehme 没错。它在上面引用的 man 页中。你根本没有没有正当理由不相信它。还有“嵌套循环”,例如 what? 谁说过嵌套循环?你这里的 cmets 仍然没有意义。
  • 非常感谢@BasileStarynkevitch。
猜你喜欢
  • 1970-01-01
  • 2012-02-28
  • 2012-03-08
  • 1970-01-01
  • 2012-11-12
  • 1970-01-01
  • 2012-01-16
  • 2012-04-20
  • 2012-10-18
相关资源
最近更新 更多