C/C++ recv 在本地服务器发送数据时挂起

C/C++ recv hangs altough local server sends data

我很难找出我的 TCP 客户端-服务器应用程序中的错误。我面临的问题是:在我的 recv 函数 do-while 循环中,如果条件为 bytes > 0,函数将永远挂起。将其替换为 bytes == NMAX,一切正常,除非 NMAX 等于 1。一些旁注:执行单个 send-recv 工作正常,但尝试执行 send-recv 然后 recv-send 永远挂起。 NMAX 是一个常量,默认设置为 4096。服务器是 运行 首先,然后是客户端。 这是我的发送功能:

ssize_t sendData(const std::string data, int fd)
{
    ssize_t total = data.length(), bytes, sent = 0;

    do
    {
        ssize_t chunk = total > NMAX ? NMAX : total;
        bytes = send(fd, data.c_str() + sent, chunk, 0);

        if (bytes == -1)
        {
            throw std::system_error(errno, std::generic_category(), "Error sending data");
        }

        total -= bytes;
        sent += bytes;
    } while (total > 0);

    return sent;
}

这是我的接收函数:

std::string recvData(int fd)
{
    ssize_t bytes;
    std::string buffer;

    do
    {
        std::vector<char> data(NMAX, 0);
        bytes = recv(fd, &data[0], NMAX, 0);

        if (bytes == -1)
        {
            throw std::system_error(errno, std::generic_category(), "Error receiving data");
        }

        buffer.append(data.cbegin(), data.cend());
    } while (bytes > 0); // Replacing with bytes == NMAX partially fixes the issue, why?

    return buffer;
}

这是客户端的主要功能:

std::cout << "Sent " << sendData(data) << " bytes\n";
std::cout << "Received: " << recvData() << "\n";

这是服务器的主要功能:

std::cout << "Received: " << recvData(client) << "\n";
std::cout << "Sent " << sendData("Hello from the server side!", client) << " bytes\n";

你的程序的问题是接收方不知道总共要接收多少字节。因此它将无休止地尝试读取更多字节。

它“挂起”的原因是您执行了阻塞系统调用 (recv),只有在至少再接收到 1 个字节时才会解除阻塞。但是,由于对等方不会发送更多数据,所以这永远不会发生。

要解决此问题,您需要为您的数据设置一个正确的 wire-format,它指示传输的数据有多大,或者它的开始和结束位置。一种常见的方法是在数据前加上二进制形式的长度(例如,大端格式的 32 位 unsigned int)。另一种方法是在数据中使用指示符来指示数据结束(例如 HTTP 中的 \r\n\r\n 换行符)。

顺便说一句:您的 send 函数对于 data.length() == 0 的情况并不理想。在这种情况下,您使用 0 字节执行 send 系统调用 - 这是不必要的。