HTTP-клиент получает «Сброс соединения по одноранговой сети» (TCP RST) с некоторых серверов, но не с других - PullRequest
0 голосов
/ 19 августа 2011

Я пишу простой HTTP-клиент и столкнулся с проблемой - некоторые HTTP-серверы принудительно сбрасывают, вызывая ошибку «Сброс соединения по одноранговой сети».Многие HTTP-серверы корректно закрывают соединение, хотя, похоже, ни один из них не поддерживает его в рабочем состоянии.

Однако я уверен, что это мой клиент, потому что клиенты HTTP, использующие очень похожий исходный код, не демонстрируют такого же поведения: ихсоединения с теми же серверами либо изящно закрыты, либо поддерживаются в рабочем состоянии.

В чем причина этой, казалось бы, противоречивой проблемы?

Соответствующий код:

/* socket */
if ((context->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
    perror("Failed to create socket");
    exit(-1);
}

/* connect */
if (connect(context->socket, &context->tx_addr, sizeof(struct sockaddr)) != 0) {
    perror("Couldn't connect to server");
    exit(-1);
}

/* create header */
snprintf(context->packet, BUFF_SIZE,
         "GET %s HTTP/1.1\r\n" \
         "Host: %s\r\n\r\n", 
         conf->request, conf->host);

/* send header */
if ((sendto(context->socket, context->packet, BUFF_SIZE, 0, 
            NULL, 0))) != BUFF_SIZE) {
    perror("Failed to send");
    exit(-1);
}

/* receive response */
do {
    if ((received = recvfrom(context->socket, context->packet, BUFF_SIZE, 0, NULL, 
                             NULL)) < 0) {

        /* THIS is where RST occurs with some servers */

        perror("Failed to receive");
        exit(-1)
    }

    if (received >= 0)     
            context->packet[received] = '\0';
    printf("%s", context->packet);

} while (received > 0);

1 Ответ

0 голосов
/ 19 августа 2011

После некоторого расследования стало очевидно, что мои HTTP-запросы были искажены.

Проблема заключается в следующем коде:

/* create header */
snprintf(context->packet, BUFF_SIZE,
         "GET %s HTTP/1.1\r\n" \
         "Host: %s\r\n\r\n", 
         conf->request, conf->host);

/* send header */
if ((sendto(context->socket, context->packet, BUFF_SIZE, 0, 
            NULL, 0)) != BUFF_SIZE) {
    perror("Failed to send entire buffer");
    exit(-1);
}

Обратите внимание, что BUFF_SIZE байтов из буфера отправляютсяхотя мы почти наверняка не заполним весь буфер при создании заголовка с snprintf.Мусор, проходящий через сгенерированный заголовок, также передавался.Некоторые серверы просто игнорировали неверный запрос, другие просто отказывались и сбрасывали (RST) соединение.

Просто измените код отправки на что-то вроде этого, чтобы решить проблему:

/* assuming context->packet is a string */
int len = strlen(context->packet);
int sent = 0, total = 0;

while (total < len) {
    if ((sent = sendto(context->socket, context->packet + total, 
                       len - total, 0, NULL, 0)) <= 0) {
        perror("Failed to send");
        exit(-1);
    }
    total += sent;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...