0

httpクライアントの作成についてサポートが必要です。Webサーバーからデータを受信しようとすると問題が発生します。recv()呼び出しは、プログラムをブロックします。より良い方向性は非常に役立ちます。以下にコードを投稿します。

if ( argc != 2 )
{
    cerr << "Usage: " << argv[0];
    cerr << " <URI>" << endl;
    return 1;
}
else
{
    uri_string = argv[1];
}

// Create URI object and have it parse the uri_string
URI *uri = URI::Parse(uri_string);

if ( uri == NULL )
{
    cerr << "Error: Cannot parse URI." << endl;
    return 2;
}

// Check the port number specified, if none use port 80
unsigned port = 80;
if ( uri->Is_port_defined() )
{
    port = uri->Get_port();
}

// Create TCP socket and connect to server
int tcp_sock = socket( AF_INET, SOCK_STREAM, 0 );
if ( tcp_sock < 0 )
{
    cerr << "Unable to create TCP socket." << endl;
    return 3;
}

sockaddr_in server;
socklen_t slen = sizeof(server);

server.sin_family = AF_INET;
server.sin_port = htons( port );
hostent *hostp = gethostbyname( uri->Get_host().c_str() );
memcpy( &server.sin_addr, hostp->h_addr, hostp->h_length );

if ( connect( tcp_sock, (sockaddr*)&server, slen ) < 0 )
{
    cerr << "Unable to connect to server via TCP." << endl;
    close( tcp_sock );
    return 4;
}

// Build HTTP request to send to server
HTTP_Request *request = HTTP_Request::Create_GET_request( uri->Get_path() );
request->Set_host( uri->Get_host() );
string request_string = "";
request->Print( request_string );

//cout << request_string << endl;

// Send it to the server, wait for reply and use HTTP_Response to get reply
send( tcp_sock, &request_string, sizeof(request_string), 0 );

char recv_buffer[1024];
int bytes_recv = 0;
while ( bytes_recv < 1024 )
{
    int recv_len = recv( tcp_sock, recv_buffer + bytes_recv,
        1024 - bytes_recv, 0 );
    if ( recv_len == -1 )
    {
        cerr << "Error receiving response from server." << endl;
        close( tcp_sock );
        return 5;
    }
    bytes_recv += recv_len;
}


HTTP_Response *response = HTTP_Response::Parse(recv_buffer, bytes_recv);
string response_string = "";
response->Print( response_string );
cout << response_string << endl;

return 0;

}

4

5 に答える 5

3

ブロッキング TCP/IP ソケットを使用していますが、読み取るバイト数を知るために HTTP 応答の「Content-Length」ヘッダーを確認していません。現在の読み取りロジックは、最大 1024 バイトが受信されるまでループで recv() を呼び出しています。サーバーが送信するのが 1024 バイト未満の場合、recv() を何度も呼び出して要求するバイト数が多すぎるため、無期限にブロックされます。

于 2009-10-20T20:03:46.683 に答える
1

recv()応答があるまでブロックすることになっています。リクエストを正しく書き込んでいて、サーバーがそれに応答していることは確かですか? ファイル記述子をノンブロッキング モードにして、select()orを使用してテストすることは可能poll()ですが、私の推測では、プロトコルのバグがどこかにあるだけです。あなたが期待している動作は何ですか?

于 2009-10-16T22:01:05.030 に答える
0

content-lengthフィールドにあるものを多くのバイトで受け取る必要があります。次の行を次のように変更する必要がありますif ( recv_len == -1 )

if ( recv_len <= 0 ) break;
else if ( recv_len == -1 )

0は、すべてのデータを送信した後にサーバーが切断されるときです。

于 2010-01-14T10:46:05.977 に答える
0

これは問題ですか?

クライアントが正常な場合。
GUIの場合、データを取得するスレッドはUIスレッドとは異なる必要があります。

しかし、解決策はselect()を使用する
ことです。これにより、ポートから読み取るものがあるかどうかがわかります。
したがって、待機中に他の作業を行うことができます。

于 2009-10-16T21:57:39.200 に答える
0

HTTP リクエストは空行で終了する必要があります。


GET / HTTP/1.1
Host: blah.com
                    <- this here is an empty line

あなたのコードはそれをしていないようです (おそらくrequest->Print(request_string + "\n")と言うべきです。

トピック外: C ですぐに利用できる HTTP クライアントがあることをご存知ですか? (libcurl など)。

于 2009-10-17T06:01:15.470 に答える