2009-01-10 7 views
2

En plus de mon post précédent sur Creating a web server in pure C, j'ai quelques problèmes avec la fonction d'envoi. Voici deux extraits de code:C, HTTP 1.1 et Socket Envoyer des problèmes

int Send(char *message) 
{ 
     int length, bytes_sent; 
     length = strlen(message); 

     bytes_sent = send(connecting_socket, message, length, 0); 

     return bytes_sent; 
} 

Ce code envoie void * à la prise de courant. Fonctionne comme un charme!

Maintenant vient ici le SendHTML

void SendHTML(char *Status_code, char *Content_Type, char *HTML) 
{ 
     char *head = "\r\nHTTP/1.1 "; 
     char *content_head = "\r\nContent-Type: "; 
     char *server_head = "\r\nServer: PT06"; 
     char *length_head = "\r\nContent-Length: "; 
     char *date_head = "\r\nDate: "; 
     char *newline = "\r\n"; 
     char Content_Length[100]; 
     int content_length = strlen(HTML); 

     sprintf(Content_Length, "%i", content_length); 

     char *message = malloc((
       strlen(head) + 
       strlen(content_head) + 
       strlen(server_head) + 
       strlen(length_head) + 
       strlen(date_head) + 
       strlen(newline) + 
       strlen(Status_code) + 
       strlen(Content_Type) + 
       strlen(Content_Length) + 
       content_length + 
       sizeof(char)) * 2); 

     if (message != NULL) 
     { 
       time_t rawtime; 

       time (&rawtime); 

       strcpy(message, head); 

       strcat(message, Status_code); 

       strcat(message, content_head); 
       strcat(message, Content_Type); 
       strcat(message, server_head); 
       strcat(message, length_head); 
       strcat(message, Content_Length); 
       strcat(message, date_head); 
       strcat(message, (char*)ctime(&rawtime)); 
       strcat(message, newline); 
       strcat(message, HTML); 

       Send(message); 

       free(message); 
     }  
} 

Si je devais ajouter

Send("Oh end of HTML Sending eh?"); 

après Send(message) et avant free(message), cela ne soit pas envoyé au navigateur? J'ai pensé que cela pourrait être un problème de HTTP 1.1, est-ce que le RFC dit que je ne peux faire qu'un seul Send? Est-ce que le navigateur Ferme la connexion après avoir reçu le premier message?

Comment puis-je résoudre ce que je puisse faire ce qui suit:

SendHTML("200 OK", "text/plain", "HAaaaii!!"); 
Send("lolwut?"); 

Cela devrait entraîner la projection du navigateur:

HAaaaii !! lolwut?

Répondre

6

Puisque vous envoyez la longueur du contenu, le navigateur n'acceptera plus de contenu après "HAaaaii !!" et interprétera donc le "lolwut?" dans le cadre de la réponse à sa prochaine demande, ce qui échouera bien sûr.

Vous pouvez ignorer l'envoi d'une longueur de contenu, mais cela signifie que vous n'utilisez pas keep-alive et que vous ne pouvez donc pas gérer plus d'une requête par connexion TCP.

La gestion de plus d'un échange Demande-Réponse par connexion TCP peut accélérer considérablement la vitesse de navigation, car une page Web normale est constituée de plusieurs ressources distinctes, dont chacune devra être demandée séparément. Et puisque l'établissement d'une connexion TCP prend au moins 3 allers-retours, cela ajouterait un délai supplémentaire inutile pour chaque ressource.

+0

Ce n'est pas bon, n'est-ce pas? –

4

Dans votre variable head, il ne doit pas y avoir de ligne "\r\n". C'est probablement ce qui cause le problème. En outre, lorsque vous envoyez votre message, vous ne réservez pas suffisamment d'espace pour la date et l'heure (26 octets selon la documentation de ctime(3)), de sorte que vous écrasez presque certainement votre mémoire tampon et causez une corruption du tas.

Si vous souhaitez commencer à envoyer des données avant de connaître la longueur du contenu, vous pouvez utiliser le chunked transfer encoding. L'encodage de transfert en bloc dit: «Je vais continuer à vous donner un tas de données en morceaux, et je peux vous dire combien de temps chaque morceau est, mais je ne sais pas combien de morceaux il y a jusqu'à ce que j'en ai fini. " Par exemple, Google utilise l'encodage de transfert en bloc. Voici une trace d'une requête HTTP pour la page d'accueil Google, généré avec cURL:

curl www.google.com --trace-ascii - 
(en-tête ciselée - mais sans en-tête Content-Length)

Le flux de données est constitué de la taille de morceau (en hexadécimal) suivi d'un CRLF, puis des octets de données.Dans ce cas, il n'y avait qu'un seul morceau, mais il aurait facilement pu y en avoir plus. Après le dernier bloc, une taille de bloc de 0 est transmise, indiquant le dernier bloc.

0

Ajoutez-vous un retour à la ligne après chaque en-tête?

Vous pouvez tester votre application en utilisant telnet, bien sûr et voir quelle est la sortie.

Non, il n'est pas nécessaire d'avoir un seul envoi. Supposons en streaming un fichier de 2 Go. Ce n'est tout simplement pas logique.

+0

Exactement mes pensées. Telnet me donne les bonnes choses :) –

Questions connexes