Почему TCP-пакеты постоянно не доходят до сервера, когда клиент их благополучно отправляет?

У меня есть простой клиент-сервер, где кажется, что TCP-пакеты, которые я отправляю от клиента, не доходят до сервера.

Обычно все работает нормально, но когда я запускаю 50 потоков на клиенте, чтобы «одновременно» поразить сервер одним и тем же небольшим пакетом данных (всего 39 байт), сервер не получает все байт. Еще более странно то, что он очень постоянен в том, как он их не получает... принимается только 5 байтов.

Я использую tcpdumpи tcpflowдля захвата того, что происходит на обоих концах ( если вы не знакомы с потоком tcp, он удаляет огромное количество TCP SYN /ACK/FIN/etc шум из потока TCP и просто показывает данные, отправленные в любом направлении) .

Со стороны клиента для 50 потоков, запускающих 39-байтовый пакет, все выглядит идеально. В частности, tcpflow (который использует libpcap) показывает мне 50 идентичных передач данных:

07 B6 00 01 | 00 1E 00 00 | 

Насколько я понимаю, libpcap/tcpdump получают данные с довольно низкого уровня (ниже стека TCP), поэтому я понимаю, что данные были отправлены. нормально, или по крайней мере не застрял в буферах ядра.

Однако если посмотреть на серверную часть, то не все так идеально. Случайное число не работает, и это высокий процент.Например, из 50 подключений к сокетам 30 будут работать нормально, но для 20 из них у меня произошел сбой протокола, когда сервер socket.recvистекает по тайм-ауту в ожидании байтов (протокол указывает точную длину пакета) .

Он ОЧЕНЬпоследователен в том, как он терпит неудачу. Для случая 30/20 30 сокетов отлично принимают переданные 39 байт. Оставшиеся 20 ВСЕХ получают эти частичные данные, после чего мой socket.recvистекает по тайм-ауту:

07 B6 00 01 | 00

На каждое из 20 соединений поступает только 5 байтов, и это похоже на уровне ядра, так как tcpdump также показывает только 5 байтов.

Как это может произойти?

Эта 5-байтовая граница не является 100% совпадением. Это первая часть заголовка, а 34-байтовая полезная нагрузка идет следующей, но не поступает. На стороне клиента он разделен следующим образом.

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.sendall(HEADER)  # 5 bytes
sock.sendall(PAYLOAD) #34 bytes

и оба вызова sock.sendallзавершаются успешно в каждом потоке, как было доказано, мой журнал tcp показывает, что все 50 прогонов отлично отправляют 39 байтов «за дверь».

Есть идеи о первопричине этого? Что я упустил?

5
задан Russ 20 April 2012 в 16:40
поделиться