recv() с MSG_PEEK показывает полное сообщение, но возвращает нормально блокируемый

У меня есть неблокирующее гнездо winsock, которое recvданные в цикле.

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

Wireshark показывает пакеты, проходящие через очень хорошо; моя серверная программа, однако, работает не совсем правильно.

Как бы я это исправить?

РЕДАКТИРОВАТЬ: Уменьшение размера буфера, скажем, до 8 привело к нескольким успешным вызовам recv без MSG_PEEK.

Recv call:

iLen = recv(group->clpClients[cell]->_sock, // I normally call without MSG_PEEK
        group->clpClients[cell]->_cBuff, CAPS_CLIENT_BUFFER_SIZE, MSG_PEEK);
if(iLen != SOCKET_ERROR)
{
    ...

Гнездо есть AF_INET, SOCK_STREAM а также IPPROTO_TCP,

4 ответа

Решение

Использование setsockopt установить TCP_NODELAY ИСТИНА.

Документация Microsoft в нескольких местах гласит, что MSG_PEEK следует избегать в целом, потому что это неэффективно и неточно. использование select(), WSAAsyncSelect(), или же WSASelectEvent() вместо этого, чтобы определить, когда сокет имеет данные, доступные для чтения, затем вызвать recv() в WSARecv() на самом деле читать это.

Решение оказалось специфичным для реализации; Я знал, что длина всех пакетов, поступающих от клиента, делится на определенное количество байтов. Итак, я просто прочитал это количество байтов, пока буфер не был пуст.

Макс. количество байтов, которое вы можете получить за раз в этой ситуации, должно быть меньше максимальной длины самого длинного сообщения и должно быть GCF (величайшим общим фактором) этой длины.

Это далеко не постоянное решение, но пока работает.

Сокет TCP - это поток байтов, он не сохраняет границы сообщений вашего приложения. Как только ядро ​​может вам что-то дать, оно возвращается из опроса. Вы должны собирать полученные байты, пока у вас не будет достаточно для декодирования того, что вам нужно для декодирования.

Другие вопросы по тегам