C, HTTP 1.1 и проблемы с Socket Send - PullRequest
2 голосов
/ 10 января 2009

Как дополнение к моему предыдущему сообщению о Создание веб-сервера на чистом C , у меня возникли некоторые проблемы с функцией отправки. Вот два фрагмента кода:

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

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

        return bytes_sent;
}

Этот код отправляет void * в текущий сокет. Работает как шарм!

Теперь вот идет 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);
        }     
}

Если бы я добавил

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

после Send(message) и до free(message), это не отправляется в браузер?

Я подумал, что это может быть проблема HTTP 1.1, RFC говорит, что я могу сделать только одну Отправку? Закрывает ли браузер соединение после получения первого сообщения?

Как мне решить эту проблему, чтобы я мог сделать следующее:

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

Это должно привести к отображению в браузере:

HAaaaii !! lolwut

Ответы [ 3 ]

6 голосов
/ 10 января 2009

Поскольку вы отправляете контент длиной, браузер больше не будет принимать контент после "HAaaaii !!" и поэтому будет истолковывать "Lolwut?" как часть ответа на его следующий запрос, который, конечно, потерпит неудачу.

Вы можете пропустить отправку контента длиной, но это будет означать, что вы не используете keep-alive и, следовательно, не можете обработать более одного запроса на TCP-соединение.

Обработка более чем одного обмена запросом-ответом на одно TCP-соединение может значительно увеличить скорость просмотра, поскольку обычная веб-страница состоит из нескольких отдельных ресурсов, каждый из которых должен запрашиваться отдельно. А поскольку для установления TCP-соединения требуется не менее 3 циклов, это добавит дополнительную, ненужную задержку для каждого ресурса.

4 голосов
/ 10 января 2009

В вашей переменной head не должно быть начальных символов "\r\n". Это, вероятно, то, что вызывает проблему. Кроме того, когда вы malloc'е ваше сообщение, вы не резервируете достаточно места для даты + времени (26 байт в соответствии с документацией для ctime(3)), поэтому вы почти наверняка перезаписываете свой буфер и вызываете повреждение кучи. .

Если вы хотите начать отправку данных до того, как узнаете, что такое Content-Length, вы можете вместо этого использовать кодировку передачи chunked . Кодировка передачи чанков говорит: «Я буду продолжать давать вам кучу данных в чанах, и я могу сказать вам, сколько времени занимает каждый чанк, но я не знаю, сколько есть чанков, пока я не закончу. " Например, Google использует кодировку передачи по частям. Вот след HTTP-запроса для домашней страницы Google, созданный с помощью cURL :

curl www.google.com --trace-ascii -
(Заголовок пропущен, но заголовок Content-Length отсутствует)

Поток данных состоит из размера фрагмента (в шестнадцатеричном формате), за которым следует CRLF, а затем байты данных. В этом случае был только один кусок, но могло легко быть больше. После последней порции передается размер порции 0, что указывает на последнюю порцию.

0 голосов
/ 10 января 2009

Вы добавляете новую строку после каждого заголовка?

Конечно, вы можете протестировать ваше приложение с помощью telnet и посмотреть, что получится.

Нет, не обязательно иметь только одну отправку. Предположим, потокового файла 2 ГБ. Это просто не логично.

...