从套接字读取单个 recv() 方法期间的所有数据

Read all data during single recv() method from a socket

我正在尝试使用套接字编程连续读取数据。我使用 recv() 在套接字上接收数据。我将它存储在缓冲区中。 recv() returns 读取的字节数。以下是片段:

while (true) {
        try {
            char buff[2048];
            int bytes = recv(sockfd, buff, 2048, 0);
            buff[bytes] = '[=10=]';
            cout << strlen(buff) << endl;
            cout << bytes << endl;
            cout << "-------" << endl;
        } catch (const char *e) {
        }
    }

代码输出如下:

1
1204
-------
1
1390
-------
1
25
-------
1
1204
-------

通过 recv() 方法接收到的字节数是正确的,但我无法读取确切的数据数。如何读取单个 recv() 方法期间捕获的所有数据?

您需要像文档中那样将正确的标志传递给 recv。基于:https://man7.org/linux/man-pages/man2/recv.2.html 有标志MSG_WAITALL(自Linux 2.2)可以做你想做的事。

调用看起来像:

int bytes = recv(sockfd, buff, 2048, MSG_WAITALL);

除非您确定只收到文本,否则通过 strlen 检查接收字节的长度是错误的。

您可以创建一个 std::string_view 指向读取的数据。

while (true) {
    char buff[2048];
    int bytes = recv(sockfd, buff, 2048, 0);
    if (bytes >= 0) {
        std::string_view read { buff, bytes };
        std::cout << read << std::endl;
        std::cout << "-------" << std::endl;
    } // else?
}

函数 strlen 会将 buff 的内容视为 null-terminated 字符串,return 该字符串的长度。

行中

buff[bytes] = '[=10=]';

您在数据末尾写了一个空终止符。这样,您就确保了数据是 null-terminated.

但是,recv 读取的字节可能包含值为 0 的字节。函数 strlen 将无法区分这样的字节和实际的终止空字符。它只是 return 第一个字节位置的索引,值为 0.

这就是表达式strlen(buff)与实际数据长度不对应的原因。

因此,您不应在二进制数据上使用函数 strlen。该函数仅适用于文本数据,不能包含值为 0 的字符,但标记字符串结尾的字符除外。

而不是使用 strlen 来确定数据的长度,您应该只使用由 recv 编辑的值 return(您已将其存储在变量 bytes).只要记住这个值,就永远知道长度,所以不需要用终止空字符来标记数据的结尾。

只要recvreturn输入正值(负数表示失败),你会发现数组buff中的所有数据,return recv 的值将指定数据的长度。例如,如果您想要打印在 recv 函数调用中收到的所有数据,您可以在 recv 函数调用之后立即编写以下内容:

for ( int i = 0; i < bytes; i++ )
    cout << hex << setw(2) << setfill( '0' ) << static_cast<int>(buff[i]) << ' ';

请注意,您必须在程序的开头添加 #include <iomanip> 才能使该行生效。