2009-10-16 7 views
0

J'ai besoin d'aide pour écrire un client http. Le problème vient quand j'essaye de recevoir des données d'un serveur Web. L'appel recv() bloque le programme. Mieux direction serait extrêmement utile, je posterai mon code ci-dessous:Blocs client http sur 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; 

}

Répondre

3

Vous utilisez un socket TCP/IP bloquant, mais vous ne regardez pas l'en-tête "Content-Length" de la réponse HTTP pour connaître le nombre d'octets à lire. Votre logique de lecture actuelle appelle recv() dans une boucle jusqu'à ce que 1024 octets max aient été reçus. Si le serveur envoie moins de 1024 octets, vous allez être bloqué indéfiniment parce que vous appelez trop souvent recv() demandant trop d'octets.

+0

Merci pour la réponse, j'ai compris ce que je devais faire. – adhanlon

+0

Que se passe-t-il si la réponse n'a pas d'en-tête "content-length"? – NeDark

+0

@NeDark: Lire la RFC 2616 (http://www.ietf.org/rfc/rfc2616.txt) Section 4.4, elle vous indique quoi faire. –

0

Est-ce un problème?

Si le client est bien en ligne.
S'il s'agit d'une interface graphique, les données d'extraction de thread doivent être différentes de l'unité d'exécution de l'interface utilisateur.

Mais une solution consiste à utiliser le select()
Cela vous indiquera s'il y a quelque chose à lire sur un port.
Ainsi vous permettant de faire d'autres travaux en attendant.

1

recv() est supposé pour bloquer jusqu'à ce qu'il obtienne une réponse. Êtes-vous sûr d'écrire correctement votre requête et que le serveur y répond? Il est possible de mettre le descripteur de fichier en mode non bloquant et de le tester en utilisant select() ou poll(), mais je suppose que vous avez simplement un bug de protocole quelque part. Quel est le comportement que vous attendez?

+0

Je sais qu'il est censé bloquer jusqu'à ce qu'il obtienne une réponse, mais il faut obtenir une réponse, quand j'imprimer le message que je vous envoie à un serveur Web, il a le format suivant: GET/HTTP/1.1 Accept-Encoding: identité; q = 1.0, *; q = 0 Hôte: google.com TE: identité; q = 1.0, en bloc; q = 0, *; q = 0 Y at-il une raison pour laquelle je devrais N'obtenez pas une réponse de cela? – adhanlon

+0

Je pense que vous devez demander à votre serveur, pas moi. :) Avez-vous regardé un vidage de paquets pour vérifier que la commande arrive au serveur, génère une réponse, et revient en une seule pièce? –

0

La requête HTTP doit se terminer par une ligne vide, à savoir


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

Il semble que votre code fait pas (il devrait probablement dire request-> Imprimer (request_string + "\ n")

Hors sujet: vous savez qu'il existe des clients HTTP facilement disponibles en C, n'est-ce pas? comme libcurl).

0

Vous devez recevoir plusieurs octets dans le champ contenu-longueur. Vous devez changer de ligne: if (recv_len == -1) à:

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

car 0 est lorsque le serveur se déconnecte après l'envoi de toutes les données.

Questions connexes