Читать из сокета - PullRequest
       2

Читать из сокета

11 голосов
/ 16 июня 2010

Мне нужно прочитать из сокета AF_UNIX в буфер, используя функцию read из C, но я не знаю размер буфера.

Я думаю, что лучший способ - прочитать N байтов, пока чтение не вернет 0 (в сокете больше нет записывающих устройств). Это правильно? Есть ли способ угадать размер буфера, записываемого в сокет?

Я думал, что сокет - это специальный файл. Открытие файла в двоичном режиме и получение размера поможет мне узнать правильный размер для буфера?

Я очень плохо знаком с C, так что имейте это в виду.

Ответы [ 5 ]

18 голосов
/ 16 июня 2010

Обычным способом является использование ioctl(..) для запроса FIONREAD сокета, который вернет, сколько данных доступно.

int len = 0;
ioctl(sock, FIONREAD, &len);
if (len > 0) {
  len = read(sock, buffer, len);
}
2 голосов
/ 17 июня 2010

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

Например,

char buffer[1024];
int ptr = 0;
ssize_t rc;

struct pollfd fd = {
   .fd = sock,
   .events = POLLIN
};

poll(&fd, 1, 0); // Doesn't wait for data to arrive.
while ( fd.revents & POLLIN )
{
   rc = read(sock, buffer + ptr, sizeof(buffer) - ptr);

   if ( rc <= 0 )
      break;

   ptr += rc;
   poll(&fd, 1, 0);
}

printf("Read %d bytes from sock.\n", ptr); 
1 голос
/ 16 июня 2010

Я думаю, что лучше всего читать N байт, пока чтение не вернет 0 (нет больше писателей в розетку). Это правильный?

0 означает EOF, другая сторона закрыла соединение. Если другая сторона связи закрывает соединение, значит это правильно.

Если соединение не закрыто (несколько передач по одному и тому же соединению, болтливый протокол), тогда дело немного сложнее, и поведение обычно зависит от того, есть ли у вас сокет SOCK_STREAM или SOCK_DGRAM.

Сокеты датаграмм уже разграничены для вас ОС.

Потоковые сокеты не разделяют сообщения (все данные являются непрозрачным байтовым потоком), и при желании необходимо реализовать это на уровне приложения: например, путем определения поля размера в структуре заголовка сообщения или использования разделителя (например, '\ n 'для однострочных текстовых сообщений). В первом случае вы должны сначала прочитать заголовок, извлечь длину и, используя длину, прочитать остальную часть сообщения. В другом случае считайте поток в частичный буфер, найдите разделитель и извлеките из буфера сообщение, включая разделитель (вам может потребоваться сохранить частичный буфер, так как в зависимости от протокола можно получить несколько команд с помощью одного recv () / read ( )).

Есть ли способ угадать размер буфера на который пишется розетка?

Для потоковых сокетов нет надежного способа, поскольку другая сторона связи все еще находится в процессе записи данных. Представьте себе вполне нормальный случай: размер буфера сокета составляет 32 КБ, а запись 128 КБ. Записывающее приложение блокировало бы внутри send () / write (), ОС ожидала чтения приложением для считывания данных и, таким образом, свободного места для следующего фрагмента записанных данных.

Для сокетов дейтаграмм обычно заранее известен размер сообщения. Или можно попробовать (никогда этого не делал сам) recvmsg (MSG_PEEK) и, если MSG_TRUNC находится в возвращенных msghdr.msg_flags, попытаться увеличить размер буфера.

1 голос
/ 16 июня 2010

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

0 голосов
/ 16 июня 2010

считывать N байтов до тех пор, пока чтение не вернется 0

Да!

Одна добавленная деталь.Если отправитель не закроет соединение, сокет просто заблокирует, а не вернет.Неблокирующий сокет вернет -1 (с errno == EAGAIN), когда нечего читать;это другой случай.

Открытие файла в двоичном режиме и получение размера поможет мне узнать правильный размер для буфера?

Нет.Розетки не имеют размера.Предположим, вы отправили два сообщения по одному и тому же соединению: как долго файл?

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