У меня есть эта неприятная проблема, когда отправка нескольких больших сообщений с быстрой последовательностью с сервера Java (NIO) (под управлением Linux) клиенту приводит к усеченным пакетам. Сообщения должны быть большими и отправляться очень быстро, чтобы возникла проблема. Вот в основном то, что делает мой код (не фактический код, а более или менее то, что происходит):
//-- setup stuff: --
Charset charset = Charset.forName("UTF-8");
CharsetEncoder encoder = charset.newEncoder();
String msg = "A very long message (let's say 20KB)...";
//-- inside loop to handle incoming connections: --
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.socket().setTcpNoDelay(true);
sc.socket().setSendBufferSize(1024*1024);
//-- later, actual sending of messages: --
for (int n=0; n<20; n++){
ByteBuffer bb = encoder.encode(CharBuffer.wrap(msg+'\0'));
sc.write(bb);
bb.rewind();
}
Итак, если пакеты достаточно длинные и отправляются как можно быстрее (т. Е. В таком цикле без задержки), то на другом конце часто получается что-то вроде этого:
[COMPLETE PACKET 1]
[COMPLETE PACKET 2]
[COMPLETE PACKET 3]
[START OF PACKET 4][SOME OR ALL OF PACKET 5]
Существует потеря данных, и пакеты начинают работать вместе, так что начало пакета 5 (в этом примере) поступает в том же сообщении, что и начало пакета 4. Это не просто усечение, это выполнение сообщений вместе .
Я предполагаю, что это связано с буфером TCP или «размером окна», или что сервер здесь просто предоставляет данные быстрее, чем ОС, или сетевой адаптер, или что-то еще, может с этим справиться. Но как я могу проверить и предотвратить это? Если я уменьшу длину сообщения при использовании sc.write (), но увеличу количество повторений, я все равно столкнусь с той же проблемой. Кажется, это просто проблема с количеством данных за короткий промежуток времени. Я не вижу, чтобы sc.write () генерировал какие-либо исключения (я знаю, что в моем примере выше я не проверяю, но имею в своих тестах).
Я был бы рад, если бы я мог программно проверить, не готова ли она еще к большему количеству данных, поставить задержку и подождать, пока она не будет готова. Я также не уверен, если "sc.socket (). SetSendBufferSize (1024 * 1024);" имеет какой-либо эффект, или если бы мне нужно настроить это на стороне Linux вещей. Есть ли способ действительно «очистить» SocketChannel? В качестве неудачного обходного пути я мог попытаться явно форсировать полную отправку чего-либо, что буферизовано, каждый раз, когда я пытаюсь отправить сообщение размером более 10 КБ, например (что не часто в моем приложении). Но я не знаю ни одного способа принудительной отправки буфера (или ожидания, пока он не будет отправлен). Спасибо за любую помощь!