Как протолкнуть (т.е. сбросить) данные, отправленные в поток TCP - PullRequest
4 голосов
/ 26 июля 2011

RFC 793 говорит, что TCP определяет функцию «push», которая гарантирует, что получатель получил данные:

Иногда пользователи должны быть уверены, что все данные, которые они имеютпредставленный в ПТС был передан.Для этого определяется функция push.Чтобы гарантировать, что данные, переданные в TCP, действительно передаются, отправляющий пользователь указывает, что они должны быть переданы принимающему пользователю.Нажатие заставляет TCP быстро пересылать и доставлять данные до этой точки получателю.

Однако я не могу найти системный вызов push.Использование fsync в дескрипторе файла приводит к ошибке неверного аргумента.

Я провел эксперимент с простым сервером, который принимает соединение от клиента, ждет, а затем отправляет клиенту 26 байтов:

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

#define PORT 1234

int main(void)
{
    int server_fd;
    int client_fd;

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        return 1;
    }

    {
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(PORT);
        addr.sin_addr.s_addr = INADDR_ANY;

        if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
            perror("bind");
            return 1;
        }
    }

    if (listen(server_fd, 20) != 0) {
        perror("listen");
        return 1;
    }

    {
        struct sockaddr_in addr;
        socklen_t addrlen = sizeof(addr);

        printf("Waiting for connection on port %d\n", PORT);

        if ((client_fd = accept(server_fd, (struct sockaddr*)&addr, &addrlen)) < 0) {
            perror("accept");
            return 1;
        }

        printf("%s:%d connected\n",
               inet_ntoa(addr.sin_addr),
               ntohs(addr.sin_port));
    }

    printf("Giving client time to close connection.\n");
    sleep(10);

    {
        ssize_t sent_length;

        if ((sent_length =
             send(client_fd, "abcdefghijklmnopqrstuvwxyz", 26, 0)) < 0)
        {
            perror("send");
            return 1;
        }

        printf("Sent %Zd bytes.\n", sent_length);
    }

    printf("Closing connection to client\n");
    if (close(client_fd) != 0) {
        perror("close(client_fd)");
        return 1;
    }

    printf("Shutting down\n");
    if (close(server_fd) != 0) {
        perror("server: close(server_fd)");
        return 1;
    }

    printf("Done!\n");
    return 0;
}

Я обнаружил, что вызов send немедленно возвращает 26, даже после того, как я закрываю соединение на стороне клиента или отключаю сетевой кабель.В последнем случае данные появляются на клиенте, когда я снова подключаю кабель и жду несколько секунд (еще долго после выключения сервера).

Как обеспечить передачу данных с помощью sendполучен и подтвержден?

Ответы [ 5 ]

9 голосов
/ 26 июля 2011

Нет толчка , говорит покойный В. Ричард Стивенс;API-интерфейс стандартных сокетов не предоставляет его и не требуется для этого RFC 1122 .Вы можете установить опцию TCP_NODELAY, но это только частичное решение.

Если вы хотите быть уверены, что другой конец получил ваши данные, то пусть он отправляет подтверждение по каналу TCP.

2 голосов
/ 26 июля 2011

попробуйте добавить вызов отключения до закрытия сокета;

shutdown(client_fd,SHUT_RDWR);

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

1 голос
/ 26 июля 2011

Насколько я знаю, TCP обеспечит передачу данных на другую машину / сокет.

Но если программа на другом конце прочитала / получила доступ, данные не могут быть подтверждены с помощью стандартного сокетаAPI.Ваш другой конец (в данном случае клиент) может быть занят чем-то другим, вместо того, чтобы ждать появления данных.

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

Механизм подтверждения важен, если ваше приложение зависит от него.

0 голосов
/ 29 июля 2017

Единственный способ убедиться, что ваши данные отправлены, - получить ответ.После многих дней тестирования это единственный способ убедиться, что он «сброшен» на другую сторону.

// Получать, пока узел не закроет соединение, чтобы убедиться, что все данные отправлены

do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0){
            printf("Bytes received: %d\n", iResult);
        }
        else if (iResult == 0){
            printf("Connection closed\n");
        }
        else{
            printf("recv failed with error: %d\n", WSAGetLastError());
        }

    } while (iResult > 0);
0 голосов
/ 26 июля 2011

Вы можете немедленно принудительно отправить небольшие пакеты, отключив алгоритм Nagle, но это не гарантирует, что клиент получит его.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...