По связи через TCP в C, как вы можете указать, чтобы прекратить вызывать read () для запроса, не зная никакой предварительной информации о данных? - PullRequest
0 голосов
/ 29 ноября 2018

В настоящее время я программирую сервер на C, который общается через сокеты с использованием TCP.Предполагается, что клиент отправит {имя файла \ n} + {содержимое файла \ n}, и сервер сохранит эту информацию, а затем отправит ответ в случае успеха.Однако мы не можем быть уверены, что клиент действительно отправит правильную информацию в структурированном протоколе.

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

//buffer is a resize-able array, 
//assume it's correct + don't worry about memory leakage for now
resizeablearray_t *buffer;

char data[255];
char retry = 1; 
while (retry) {
   int bytes = read(socketfd, data, 255);
   if (bytes <= 0) {
      fprintf(stderr, "Error %s\n", strerror(errno));
      return;
   }
   push(buffer, data, bytes);
}

Поэтому перед нами огромная проблема: как мы указываем функции read () в c, что мы 'прочитали всю информацию о предыдущем звонке, и мы не должны звонить снова?

Функциональные блоки read () пока не будут прочитаны байты на сервере.Однако в нашей модели, если мы продолжим попытку чтения из-за короткого счета и в буфере ничего не останется, мы будем ждать НАВСЕГДА.

Есть ли какие-либо идеи о том, как указать перед другим вызовом read (), без какой-либо предварительной информации о входящем сообщении и его структуре, что мы можем выйти из цикла while и прекратить попытки чтения из сокета?

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Как насчет создания [простого / грубого] протокола пакета между двумя:

byte_length(4)|data(byte_length)

Когда все сделано, отправитель отправляет один окончательный пакет с byte_length, установленным в 0 (т.е. маркер EOF), чтобы указатьвсе было отправлено.

Вот примерный код:

//buffer is a resize-able array,
//assume it's correct + don't worry about memory leakage for now
resizeablearray_t *buffer;

char data[255];
char retry = 1;

void
receive(void)
{
    uint32_t size;
    int bytes;

    while (retry) {

        bytes = read(socketfd,&size,sizeof(size));
        if (bytes <= 0) {
            fprintf(stderr, "Error %s\n", strerror(errno));
            return;
        }

        // got EOF marker
        if (size == 0)
            break;

        size = ntohl(size);

        bytes = read(socketfd, data, size);
        if (bytes <= 0) {
            fprintf(stderr, "Error %s\n", strerror(errno));
            return;
        }
        push(buffer, data, bytes);
    }
}

void
sender(void)
{
    uint32_t size;
    int bytes;

    while (retry) {

        bytes = read(filefd, data, sizeof(data));
        if (bytes == 0)
            break;

        if (bytes < 0) {
            fprintf(stderr, "Error %s\n", strerror(errno));
            return;
        }

        size = htonl(bytes);
        bytes = write(socketfd, &size, sizeof(size));

        bytes = write(socketfd, data, bytes);
        if (bytes <= 0) {
            fprintf(stderr, "Error %s\n", strerror(errno));
            return;
        }
    }

    // send EOF marker
    size = 0;
    write(socketfd,&size,sizeof(size));
}
0 голосов
/ 29 ноября 2018

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

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

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

...