2014-11-24 3 views
2

Я написал программу сокета в C. Я использовал эту программу в качестве сервера чата/клиента, использующего TCP. Я попытался изменить сервер чата, чтобы использовать его в качестве HTTP-сервера, изменив порт на 80. Я ссылался на формат запроса/ответа HTTP в http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Example_session и заставлял мою программу отвечать с ответом на образец. Я пробовал URL-адресКак отформатировать ответ HTTP

http://127.0.0.1/ 

в браузере. Моя программа прочитала запрос и ответила с ответом. Сначала я использовал google-хром. Chrome не загружал страницу правильно, пока я не добавил правильную длину данных в заголовок Content-Length. После установки заголовка длины содержимого хром загрузил страницу правильно. Но Firefox не загружает страницу. Firefox не показывает никаких ошибок, но все равно загружает страницу, как будто она все еще ждет некоторых данных. Только Когда я останавливаю сервер или закрываю сокет, загружается полная страница. Я попытался выполнить rfc2616 http://tools.ietf.org/html/rfc2616 и сделал ответ точно, но результаты все же.

Запрос:

GET/HTTP/1.1 \ г \ nHost: 127.0.0.1:8080\r\nUser-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; с.в.: 33,0) Геккон/20100101 Firefox/33.0 \ г \ nAccept: текст/HTML, приложение/XHTML + XML, приложение/XML; д = 0,9, /; д = 0,8 \ г \ nAccept-Язык: ан-США, ен; д = 0,5 \ г \ nAccept-Encoding: GZIP, выкачать \ г \ nConnection: поддержания активности \ г \ п \ г \ п

Для вышеуказанного запроса моя программа записывается в сокет со следующим ответом &.

Ответ:

HTTP/1.1 200 OK \ г \ nCache-Control: нет кэша, частное \ г \ nContent-Length : 107 \ г \ nDate: пн, 24 ноября 2014 10: 21:21 GMT \ г \ п \ г \ п

Содержание:

<html><head><title></title></head><body>TIME : 1416824843 <br>DATE: Mon Nov 24 15:57:23 2014 </body></html> 

Этот ответ загружается в Chrome, но не в Firefox. Chrome мгновенно загружает страницу, а firefox ждет данных. Обратите внимание, что длина 107 данных указана в заголовке. У меня нет никаких аддонов в firefox. Моя версия firefox находится в запросе. Версия Chrome: версия 38.0.2125.111 (64-разрядная версия).

Код:

void *socket_read(void *args) 
{ 
    int socket,*s,length; 
    char buf[1024]; 
    s=(int *)args; 
    socket=*s; 
    while(1){ 
     buf[0]='\0'; 
     length=read(socket,buf,1024); 
     if(length==0) 
      break; 
     else if(length==-1){ 
      perror("Read"); 
      return; 
     } 
     else{ 
      printf("Request: %s\n",buf); 
      send_response(socket); 
     }  
    } 
    printf("End of read thread [%d]\n",socket); 
} 
int start_accept(int port) 
{ 
    int socket,csocket; 
    pthread_t thread; 
    struct sockaddr_in client; 
    socklen_t addrlen=sizeof(client); 
    pthread_attr_t attr; 
    socket=create_socket(port); 
    while(1){ 
     if((csocket=accept(socket,(struct sockaddr *)&client,&addrlen))==-1) 
     { 
      perror("Accept"); 
      break; 
     } 
     pthread_attr_init(&attr); 
     if(0!=pthread_create(&thread,&attr,socket_read,&csocket)) 
     { 
      perror("Read thread"); 
      return; 
     } 
     usleep(10000); 
    } 
} 
void send_response(int socket) 
{ 
    char buf1[1024]; 
    int content_length; 
    char buf2[1024]="<html><head><title></title></head><body>TIME : 1416824843 <br>DATE: Mon Nov 24 15:57:23 2014 </body></html>"; 
    content_length=strlen(buf2); 
    sprintf(buf1,"HTTP/1.1 200 OK\r\nCache-Control : no-cache, private\r\nContent-Length : %d\r\nDate : Mon, 24 Nov 2014 12:03:43 GMT\r\n\r\n",content_length); 
    printf("Written: %d \n",write(socket,buf1,strlen(buf1))); 
    fflush(stdout); 
    printf("Written: %d \n",write(socket,buf2,content_length)); 
    fflush(stdout); 
} 
+0

Вы хотите создать постоянное соединение? Вы уверены, что все байты отправлены? Что произойдет, если вы добавите заголовок 'Connection: close' и закроете соединение после отправки данных? – CodeCaster

+0

@CodeCaster Я хочу создать постоянное соединение. Я проверил количество байтов, написанных с использованием возвращаемого значения метода write()/send(). Если я добавлю заголовок закрытия соединения, хром загрузит страницу и закрывает соединение сокета, но Firefox все равно загружает страницу и не закрывает сокет. – smartkid

ответ

2

Я нашел проблему. Ответ неверен. Не должно быть пробелов между именем поля заголовка и двоеточием (':'). Найдено в http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2.

Мой правильный ответ

HTTP/1.1 200 OK\r\nCache-Control: no-cache, private\r\nContent-Length: 107\r\nDate: Mon, 24 Nov 2014 10:21:21 GMT\r\n\r\n 

Я поставил пробел между 'Content-Length' и ':'. Именно по этой причине Firefox проигнорировал заголовок длины контента и прочитал сокет. Chrome принял поля заголовка с пробелами, поэтому проблема не возникает в хроме.

После удаления пространства программа работает нормально.

+0

Хороший вывод. Я тестировал эти пространства, и это сработало для меня. Так или иначе ... – rodolk

0

Это фактически загружает страницу. Если вы добавите заголовок типа контента, вы увидите HTML-страницу (Content-Type: text/html; charset = UTF-8 \ r \ n)

В любом случае, как в Chrome, так и в Firefox вы увидите соединения никогда останавливается, потому что сервер не закрывает сокет. Если вы закрыли csocket, вы увидите HTML-страницу в обоих браузерах, но, как вы сказали, это должно быть постоянное соединение.

+0

Firefox загружает страницу, но ничего не показывает, пока я не закрою сервер. Это проблема. В chrome соединение никогда не останавливается, но полная страница загружается моим контентом. Я добавил заголовок Content-Type, но результаты одинаковы в firefox. Я думаю, firefox игнорирует заголовок Content-Length и ищет данные в сокете. – smartkid

+0

Странно, что работало с моим Firefox. Я протестировал его. Можете ли вы добавить в конце данных «\ r \ n» - без изменения длины контента - просто попробовать? – rodolk

+0

Я тоже пробовал. Это не работает для моего firefox. – smartkid