Как сделать запись множественных сокетов с одним активным соединением сокетов с экспресс-веб-сервером? - PullRequest
0 голосов
/ 02 января 2019

Я пытаюсь выполнить несколько запросов на запись с одним активным соединением сокета с экспресс-сервером, работающим на локальном хосте.Я делаю http-запрос на экспресс-веб-сервер, работающий на localhost.Сообщение отправляется следующим образом:

GET /temp?sensorId=1&value=71 HTTP/1.1
Content-Type: text/html; charset=utf-8
Connection: keep-alive

Я убедился, что в сообщение включен заголовок «Connection: keep-alive» (хотя в этом нет необходимости, поскольку я использую HTTP / 1.1).

Код для отправки запроса

void sendRequest (char** message, int* socket_ref) {
int total = strlen(*message);
int bytes, sent = 0;
do {
    bytes = write(*socket_ref, *message + sent, total - sent);
    if (bytes < 0) {
        perror("ERROR writing message to socket yo");
        exit(EXIT_FAILURE);
    }
    if (bytes == 0) break;
    sent += bytes;
} while (sent < total);

   printf("Data sent. %d\n\n", sent);
}

Код драйвера

 char* dummy[80] = {"GET", "localhost", "3001", "/temp", "?sensorId=1&value=71"};
        setMessage(a, dummy);
        makeRequest(a);

        getResponse(&a);
        sleep(2);

        makeRequest(a);
        getResponse(&a);

Я ожидаю получить два "71" на моем экспресс-сервере, но я только получаюпервый.Первый запрос на запись возвращает успешный ответ, но следующий не отправляет ответ (соединение http сохраняется).

Две команды записи возвращают ожидаемое количество записанных байтов.

makeRequest (a) - это оболочка для вызова sendRequest (), как показано выше.
getRequest (& a) - это оболочка для вызова read в сокете.

ОБНОВЛЕНИЕ getResponse (& a) просто вызывает следующий код

#define RESPONSE_SIZE 4096
char* receiveResponse(int* socket_ref) {
char* response = malloc(RESPONSE_SIZE);
int total, bytes, received = 0;

memset(response, 0, RESPONSE_SIZE);
total = RESPONSE_SIZE - 1;
do {
    bytes = read(*socket_ref, response + received, total - received);
    if (bytes < 0) {
        perror("ERROR reading response from socket yo");
        exit(EXIT_FAILURE);
    }
    if (bytes == 0) break;
    received += bytes;
} while (received < total);
if (received == total) {
    perror("ERROR storing complete response from socket yo");
    exit(EXIT_FAILURE);
}
return response;

}

ОБНОВЛЕНИЕ 2 Вызвав getResponse(& a) после каждого вызова makeRequest (a) появляется следующий ответ:

Data sent. 125

Response:
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Content-Length: 4
ETag: W/"4-d2PTd7kl/AFtn95E/ir6IzKjD9I"
Date: Thu, 03 Jan 2019 01:51:12 GMT
Connection: keep-alive

GOOD
Data sent. 125

Response:

Однако, если getResponse (& a) вызывается после двух makeRequest (a), тогда обе записи происходят успешно, но яполучить следующее для ответа:

Data sent. 125

Data sent. 125

Response:
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Content-Length: 4
ETag: W/"4-d2PTd7kl/AFtn95E/ir6IzKjD9I"
Date: Thu, 03 Jan 2019 02:00:43 GMT
Connection: keep-alive

GOODHTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Content-Length: 4
ETag: W/"4-d2PTd7kl/AFtn95E/ir6IzKjD9I"
Date: Thu, 03 Jan 2019 02:00:43 GMT
Connection: keep-alive

GOOD

1 Ответ

0 голосов
/ 03 января 2019

Я пытаюсь выполнить несколько запросов на запись с одним активным соединением сокета с экспресс-сервером, работающим на локальном хосте.

Ваша функция receiveResponse() не подходит для использования с постоянным (a.k.a. keep-alive) соединением. Рассмотрим этот фрагмент:

int total, bytes, received = 0;

memset(response, 0, RESPONSE_SIZE);
total = RESPONSE_SIZE - 1;
do {
    bytes = read(*socket_ref, response + received, total - received);
    if (bytes < 0) {
        perror("ERROR reading response from socket yo");
        exit(EXIT_FAILURE);
    }
    if (bytes == 0) break;
    received += bytes;
} while (received < total);

При каких условиях цикл завершается? Ну, это заканчивается

  • если заполнен приемный буфер.

  • , если read() возвращает отрицательное число, сигнализирующее об ошибке.

  • , если read() возвращает 0, сигнализируя об окончании файла.

Никакое другое внутрипрограммное условие не приводит к прекращению цикла. Каждая из первых двух возможностей вызывает сообщение об ошибке и завершение программы, поэтому, если одна из них произошла, вы бы знали (правильно?). Следовательно, вы должны видеть последнюю альтернативу ... или вы ?

Что именно означает конец файла для сокета? Как и в случае любого другого файла, это означает, что из сокета нельзя (никогда) получить больше данных - по естественным причинам, иначе вместо этого вы получите ошибку. В частности, для сокета это означает, что удаленный узел закрыл соединение или, по крайней мере, отключил свою выходную сторону этого соединения. И это именно то, что не не происходит с постоянным соединением, по крайней мере, не быстро. Когда это в конце концов произойдет, если вы так долго ждете, соединение разорвано - вам нужно установить новое, чтобы получить другой ответ.

Итак,

Я ожидаю получить два "71" на моем экспресс-сервере, но я только получение первого.

Это связано с тем, что второй запрос не предпринимается до тех пор, пока сервер не закроет соединение (циклы чтения будут блокироваться до тех пор), после чего второй запрос не может быть доставлен или, как минимум, ответ на него не может быть получен.

Первый запрос на запись дает успешный ответ, но следующий не отправляет ответ (http-соединение сохраняется в живых).

Ответ на первый запрос успешно получен, как и ожидалось. Ответ на второе не получен, поскольку второе не доставлено на сервер, что также согласуется с тем, что вы видите на стороне сервера. Я затрудняюсь объяснить, почему клиент не выдает сообщение об ошибке в этом случае, поэтому я попросил вас получить дополнительную информацию, но я уверен, что getResponse() будет возвращаться успешно не более одного раза для любого данного соединения, и после этого маловероятно, что любые дальнейшие запросы могут быть успешно отправлены через соединение.

Вы прокомментировали,

если я прокомментирую первый вызов getResponse (& a), обе записи пройдут успешно. Теперь последний ответный вызов возвращает строку, в которой два ответа объединены.

Это совершенно естественно. Вы используете постоянное соединение, поэтому ответ на каждый успешно доставленный запрос можно прочитать с одного и того же соединения. В этом случае вы откладываете чтение данных до тех пор, пока оба запроса не будут отправлены, поэтому сервер отвечает на оба.

Для обработки постоянных соединений HTTP-клиент должен иметь возможность распознавать границы сообщений, отличные от EOF. Стандартный способ сделать это - проанализировать заголовки ответа по мере их поступления, найти и проанализировать длину содержимого между ними, а после достижения тела ответа прочитать число байтов, заданное длиной содержимого.

...