2013-08-06 2 views
4

TCP_NODELAY - это опция для быстрой отправки TCP-пакетов независимо от их размера. Это очень полезная опция, когда вопросы скорости, однако, мне любопытно, что он будет делать с этим:Как TCP_NODELAY влияет на последовательные вызовы write()?

Socket socket = [some socket]; 
socket.setTcpNoDelay(true); 
OutputStream out = socket.getOutputStream(); 
out.write(byteArray1); 
out.write(byteArray2); 
out.write(byteArray3); 
out.flush(); 

Я пытался найти то, что на самом деле делает флеш на SocketOutputStream, но, насколько я знаю сейчас, это ничего не делает. Я надеялся, что это скажет сокет «отправить все ваши буферизованные данные сейчас», но, к сожалению, нет, это не так.

Мой вопрос: являются ли эти 3 байтовых массива отправлены в одном пакете? Я знаю, что у вас нет большого контроля над тем, как TCP создает сетевой пакет, но есть ли способ сказать сокету (по крайней мере, попытаться) упаковать эти байтовые массивы, поэтому избежать сетевых издержек? Можно вручную упаковать байтовые массивы и отправить их одним звонком в write help?

+3

«TCP_NODELAY .. полезен, когда скорость имеет значение». * NO *. Это полезно, когда * отзывчивость * имеет значение (получение отправленного байта как можно скорее). TCP_NODELAY может * уменьшить * общую пропускную способность, посылая * совокупные данные * относительно * НЕВИДИМО *. Буферизация хорошая: когда это возможно. IMHO ... – paulsm4

+2

ПРЕДЛОЖЕНИЕ: Получите копию [wireshark] (http://www.wireshark.org) и проследите пакеты, фактически отправленные для пары тестовых программ сокетов. – paulsm4

+0

Да, это то, что я имел в виду. ;-) Я знаю, что это неэффективно, но в моем случае _responsiveness_ важнее ожидания достаточного количества данных. Однако для случая, о котором идет речь, я хочу его оптимизировать, потому что отправка одиночных байтовых массивов не имеет особого смысла, это важно для всех из них. – AyCe

ответ

6

Мой вопрос: являются ли эти 3-байтовые массивы отправленными в один пакет?

Как вы отключили алгоритм Nagle, почти наверняка нет, но вы не можете быть на 100% уверены.

Я знаю, что вы не имеете больше контроля над тем, как TCP строит сетевой пакет, но есть ли способ сказать сокет (по крайней мере, попытаться) упаковать эти массивы байтов

Да , Не надо отключить алгоритм Нэгла.

так избежать сетевых накладных расходов? Можно вручную упаковать байтовые массивы и отправить их в один звонок, чтобы написать справку?

Да, или еще проще просто обернуть выходной разъем потока в BufferedOutputStream и вызвать flush(), когда вы хотите, чтобы данные были отправлены, в соответствии с вашим настоящим кодексом. Вы правы, что flush() ничего не делает на выходном потоке сокета, но он сбрасывает BufferedOutputStream.

+0

Как я уже сказал в комментарии, мне нужно TCP_NODELAY для моего приложения, поэтому отключить это не вариант для меня. Я фактически использую 'BufferedOutputStream' для отправки уже, это гарантирует, что данные будут отправляться только после вызова' flush() '? – AyCe

+0

Да, если буфер BufferedOutputStream достаточно велик для хранения всех ожидающих данных. (По умолчанию 8 тыс.). Однако если вы ожидаете * получить * данные все вместе, подумайте еще раз. Это не гарантирует. Вы все еще должны зацикливаться на приемнике, пока не получите все, что вам нужно, или используйте 'DataInputStream.readFully()', если вам известна ожидаемая длина. – EJP

+1

Хорошо, хорошо! Конечно, я знаю, что не могу получить его как «пакет», как я мог с UDP. Все эти байтовые массивы являются отдельными сообщениями, но они имеют смысл только после получения последнего из них. Поэтому было бы бессмысленно отправлять их как отдельные пакеты. – AyCe

1

Может ли вручную упаковать байтовые массивы и отправить их в один звонок, чтобы написать справку?

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

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

Если вы отключите nagle и выполните отдельные системные вызовы (помните, что ОС управляет сокетами, а не вашим приложением или java), вы просите ОС отправить их по отдельности. OS не имеет понятия, что вы собираетесь переписать запись еще раз с некоторыми данными.

+0

Спасибо за информацию! Я объединять байтовые пакеты, и это, кажется, работает очень хорошо. – AyCe

+0

@AyCe, если вы считаете, что это отвечает на ваш вопрос лучше, чем другой ответ, я был бы признателен, если бы вы переключили принятый ответ. – xaxxon

+1

Вы отлично отвечаете, вы объясняете разделение OS/Java на Sockets и также даете ответ на мой второстепенный вопрос, отвечая на мой основной вопрос (если эти 3 байтовые массивы, скорее всего, будут отправлены в одном пакете) также косвенно. EJP также отвечает на оба вопроса, но также дает совет использовать «BufferedOutputStream», поэтому я чувствую, что этот ответ более совершенен :) – AyCe

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