1

我注意到这个问题已经被问过很多次了,但似乎没有一个解决方案适用于我。在继续之前,我将为您发布一些代码:

    // Await the response and stream it to the buffer, with a physical limit of 1024 ASCII     characters
    stringstream input;
    char buffer[4096*2];
    while (recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL) > 0)
        input << buffer;
    input << '\0';

    // Close the TCP connection
    close(sock);
    freehostent(hostInfo);

这是我的要求:

    string data;
    {
        stringstream bodyStream;

        bodyStream
            << "POST /api/translation/translate HTTP/1.1\n"
            << "Host: elfdict.com\n"
            << "Content-Type: application/x-www-form-urlencoded\n"
            << "Content-Length: " << (5 + m_word.length())
            << "\n\nterm=" << m_word;

        data = bodyStream.str();
    }

    cout << "Sending HTTP request: " << endl << data << endl;

我对这种编程非常陌生(并且堆栈溢出 - 宁愿将它拖出并将我的头撞到墙上,直到我自己解决问题但我在这里迷路了!)并且非常感谢帮助找出为什么需要这样长!我已经研究过将其设置为非阻塞,但在使其按预期工作时遇到了问题。虽然也许这里的人可以为我指出正确的方向,但如果非阻塞路线是我需要走的路。

我看到很多人喜欢使用库,但我想学习这样做!

我也是在 mac 上编程和使用套接字的新手。可能不是最好的第一次项目,但我现在开始了!所以我希望继续:) 任何帮助都会很好!

先感谢您!

4

2 回答 2

2

之所以需要很长时间才能接收,是因为你告诉系统等到它收到你要求的所有数据,即8k字节,或者连接出现错误或关闭。这就是旗帜的MSG_WAITALL作用。

对此的一种解决方案是使套接字成为非阻塞的,并在循环中进行连续读取,直到出现错误或连接关闭。

如何使套接字非阻塞取决于平台,在 Windows 上使用该ioctlsocket功能完成,在 Linux 或类似系统上使用该fcntl功能完成:

int flags = fcntl(sock, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(sock, F_SETFL, flags);

然后你像这样从套接字读取:

std::istringstream input;

for (;;)
{
    char buffer[256];
    ssize_t recvsize;

    recvsize = recv(sock, buffer, sizeof(buffer) - 1, 0);
    if (recvsize == -1)
    {
        if (errno != EAGAIN && errno != EWOULDBLOCK)
            break;  // An error
        else
            continue; // No more data at the moment
    }
    else if (recvsize == 0)
        break;  // Connection closed

    // Terminate buffer
    buffer[recvsize] = '\0';

    // Append to input
    input << buffer;
}

上述循环的问题是,如果没有收到任何数据,它将永远循环。


但是,您的代码中有一个更严重的问题:您接收到缓冲区,然后将其附加到stringstream,但您没有终止缓冲区。您不需要终止流中的字符串,它会自动完成,但您确实需要终止缓冲区。

这可以这样解决:

int rc;
while ((rc = recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL)) > 0)
{
    buffer[rc] = '\0';
    input << buffer;
}
于 2012-07-31T11:30:41.907 回答
1

发生这里的问题是因为您指定了MSG_WAITALL标志。它强制recv保持阻塞,直到收到所有指定的字节(sizeof(buffer) - 1在您的情况下,而对方发送的消息显然更小)或发生错误并返回 -1 并errno适当设置变量。

我认为,一个更可取的选择是recv在循环中没有任何标志,直到另一端的套接字关闭(recv 返回 0)或收到一些分隔符。

但是,您应该小心使用input << buffer,因为recv每次迭代可能只返回一小部分数据(例如,20 个字节),因此您应该将这些数据量准确地放入字符串流。接收到的字节数由recv.

于 2012-07-31T11:38:39.957 回答