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機能です。

これに対する 1 つの解決策は、ソケットをノンブロッキングにし、エラーが発生するか接続が閉じられるまでループで連続読み取りを行うことです。

ソケットをブロックしないようにする方法は、プラットフォームによって異なります。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フラグを指定しているためです。指定されたすべてのバイトが受信されるまで(あなたの場合、相手から送信されたメッセージが明らかに小さい間)、エラーが発生し、変数が適切に設定されて-1が返されるまで、recvブロックされたままになります。sizeof(buffer) - 1errno

recvより好ましいオプションは、反対側のソケットが閉じられる (recv が 0 を返す) か、セパレーターが受信されるまで、ループ内でフラグなしで発生させることだと思います。

ただし、各反復でデータのごく一部 (20 バイトなど) しか返されない可能性があるinput << bufferため、の使用には注意が必要です。そのため、正確にこの量のデータを文字列ストリームに配置する必要があります。recv受信したバイト数は によって返されrecvます。

于 2012-07-31T11:38:39.957 に答える