Чтение из сокета в al oop? - PullRequest
0 голосов
/ 27 мая 2020

Я создаю TCP сервер / клиент в C.

Идея состоит в том, чтобы сервер отправлял относительно большой объем информации. Однако буфер в клиенте имеет размер только 512 (я не хочу увеличивать этот размер), и, очевидно, информация, отправляемая сервером, больше этого размера. Представим 812 байт.

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

Вот что должно быть произошло:

1) Создайте сервер и заблокируйте системный вызов read () (ожидая, пока клиент что-то напишет);

2) Создайте клиента и напишите что-нибудь в сокет , а затем блокируется на read (), ожидая ответа сервера;

3) Вызов read () сервера возвращается, и теперь сервер должен отправить этот большой объем данных, используя следующий код (после создание нового процесса):

dup2(new_socketfd, STDOUT_FILENO); // Redirect to socket

execlp("/application", "application", NULL); // Application that prints the information to send to the client

Представим, что «приложение» напечатало 812 байт данных в сокет.

4) Теперь клиент должен прочитать 812 байт с размером буфера из 512. Это моя проблема.

Как мне подойти к этой проблеме? Мне было интересно, могу ли я сделать al oop и читать, пока нечего читать, 512 на 512 байт. Но как только читать нечего, клиент блокирует read ().

Есть идеи?

1 Ответ

0 голосов
/ 27 мая 2020

recv будет заблокирован, если в потоке нет данных. Любые данные, извлеченные из потока, длина возвращается из recv. Вы можете написать простую функцию для извлечения полных данных, просто используя переменную смещения и проверяя возвращаемое значение.

Подойдет такая простая функция.

ssize_t readfull(int descriptor,char* buffer, ssize_t sizetoread){
    ssize_t offset = 0;
    while (offset <sizetoread) {
        ssize_t read = recv(descriptor,buffer+offset,sizetoread-offset,0);
        if(read < 1){
            return offset;
        }
        offset+=read;
    }
    return offset;
}

Также серверы обычно отправляют своего рода EOF, когда данные закончены. Либо сервер может сначала отправить длину сообщения для чтения, которая имеет постоянный размер, четыре или восемь байтов, а затем он отправит данные, чтобы вы заранее знали, сколько читать. Или, например, в случае HTTP, есть поле длины содержимого, а также разделители '\ r \ n'.

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

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

Итак, ваш сервер может выглядеть так:

int sizetosend = arbitrarysize;
send(descriptor,(char*)&sizetosend,sizeof(int),0);

send(descriptor,buffer,sizetosend,0);

Затем на стороне клиента прочтите четыре байта, затем буфер.

int sizetoread = 0;
ssize_t read = recv(descriptor,(char*)&sizetoread,sizeof(int),0);
if(read < 4)
  return;

//Now just follow the code I posted above
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...