2016-08-30 2 views
4

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

Я использую приведенный ниже код для чтения из измерительной системы. Эта система обеспечивает передачу данных с частотой 15 Гц. READ_TIMEOUT_MS имеет значение 200 Кроме того, READ_BUFFER_SIZE имеет значение 40000. Все работает нормально, но что происходит, read() возвращает 15 раз в секунду с 1349 байтами.

Читая Pitfall 5 в следующей документации, которую я бы ожидать, что буфер заполнен полностью:

http://www.ibm.com/developerworks/library/l-sockpit/

Init:

sock=socket(AF_INET, SOCK_STREAM, 0); 
if (socket < 0) 
{ 
    goto fail0; 
} 

struct sockaddr_in server; 
server.sin_addr.s_addr = inet_addr(IPAddress); 
server.sin_family = AF_INET; 
server.sin_port = htons(Port); 
if (connect(sock,(struct sockaddr *)&server, sizeof(server))) 
{ 
    goto fail1; 
} 

struct timeval tv; 
tv.tv_sec = READ_TIMEOUT_MS/1000; 
tv.tv_usec = (READ_TIMEOUT_MS % 1000) * 1000; 
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval))) 
{ 
    goto fail1; 
} 

return true; 

fail1: 
    close(sock); 
    sock = -1; 
fail0: 
    return false; 

Read:

unsigned char buf[READ_BUFFER_SIZE]; 
int len = read(sock, buf, sizeof(buf)); 
if (len <= 0) 
{ 
    return NULL; 
} 

CBinaryDataStream* pData = new CBinaryDataStream(len); 
pData->WriteToStream(buf, len); 
return pData; 

Надеюсь, этот вопрос не дублируется, будь потому что я искал ответ, прежде чем я спросил. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

+0

Он возвращается всякий раз, когда операционная система чувствует, как он. Вы должны быть готовы получить меньше байтов, чем хотите. Pitfall 5 на самом деле подразумевает это. Диаграмма показывает чтение 1024 байта, но в тексте говорится об этом, возвращающем 200 байт. –

+0

Возможно, вы захотите заглянуть в ['select'] (http://man7.org/linux/man-pages/man2/select.2.html) для более легкого контролируемого таймаута. – user4581301

+0

@ н.м .: Я понял это поведение ОС. Но мне интересно, почему вызов 'read()' каждый раз возвращает желаемое количество байтов. – bushmills

ответ

1

Я подозреваю, что вы используете Linux. manpage for read says:

В случае успеха, число байтов, считанных (ноль означает конец файла), а позиция файла продвигается по этому номеру. Это не ошибка, если это число меньше количества запрошенных байтов;

TCP-сокеты моделируют байтовый поток, а не протокол или протокол, ориентированный на сообщения. Вызов чтения в сокете возвращается, если в буфере приложения есть какие-либо данные. В принципе, данные поступают в сетевую карту, затем передаются в пространство ядра, где оно обрабатывается ядром и сетевым стеком. Наконец, syscall read получает данные из пространства ядра и переносит их в пространство пользователя.

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

Кроме того, вызов может возвращаться без чтения ничего, поскольку ОС была прервана. Это происходит довольно часто при отладке или профиле приложения. Вы должны справиться с этим в своем прикладном уровне.

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

+0

Спасибо за ваш ответ! Да, я работаю на платформе Linux. Вы говорите: «Вызов для чтения возвращается, как только в буфере чтения есть что-то». Означает ли это, что байты, возвращаемые 'read()' просто "совпадают" в моем случае по какой-либо причине? – bushmills

+1

@ bushmills Существует множество веб-сайтов, описывающих путь дыры от NIC до приложения, например. http://www.cubrid.org/blog/dev-platform/understanding-tcp-ip-network-stack/. – Jens

+0

@ bushmills Да, вызов read может получить произвольное количество байтов до поставленного максимума. Это может быть 1. Вы должны реализовать кадрирование себя в приложении, например. путем чтения в цикле, пока вы не получите ожидаемое количество байтов для сообщения. – Jens

Смежные вопросы