2015-05-07 6 views
0

Я пытаюсь передать текстовый файл на другой сервер с использованием TCP, и он ведет себя по-другому, чем ожидалось. Код отправки данных является:InputStream in.read() ведет себя иначе, чем ожидалось

 System.out.println("sending file name..."); 
     String outputFileNameWithDelimiter = outputFileName + "\r\n"; //These 4 lines send the fileName with the delimiter 
     byte[] fileNameData = outputFileNameWithDelimiter.getBytes("US-ASCII"); 
     outToCompression.write(fileNameData, 0, fileNameData.length); 
     outToCompression.flush(); 

     System.out.println("sending content..."); 
     System.out.println(new String(buffer, dataBegin, dataEnd-dataBegin)); 
     outToCompression.write(buffer, dataBegin, dataEnd-dataBegin); //send the content 
     outToCompression.flush(); 

     System.out.println("sending magic String..."); 
     byte[] magicStringData = "--------MagicStringCSE283Miami".getBytes("US-ASCII"); //sends the magic string to tell Compression server the data being sent is done 
     outToCompression.write(magicStringData, 0, magicStringData.length); 
     outToCompression.flush(); 

Поскольку это TCP, и вы не можете отправлять отдельные пакеты, как и в UDP, я ожидал, все данные, чтобы быть во входном потоке, и я мог бы просто использовать разделители для разделения имя файла, содержимое и конец строки, а затем каждый in.read() просто даст мне следующий последующий объем данных.

Вместо этого данные я получаю на каждое чтение:

On the first in.read() byteBuffer appears to only have "fileName\r\n". 
On the second in.read() byteBuffer still has the same information. 
On the third in.read() byteBuffer now holds the content I sent. 
On the fourth in.read() byteBuffer holds the content I sent minus a few letters. 
On the fifth in.read() I get the magicString + part of the message. 

Я промывке на каждый отправить с веб-сервера, но входные потоки, похоже, не для реализации Смываемый.

Может ли кто-нибудь объяснить, почему это происходит?

EDIT: Вот как я читаю вещи. В основном это в цикле, а затем записывается в файл.

in.read(byteBuffer, 0, BUFSIZE); 
+0

Можете ли вы показать, как вы читаете с 'in' на стороне клиента? У меня есть сильное подозрение, что вы не проверяете возвращаемое значение 'in.read() '(количество байтов, фактически считанных из потока). – dddsnn

+0

Я не, но зачем это проверять? Разве это не просто позволит мне отлаживать его (мне кажется, что проблема in.read() заключается в том, что, увидев, что счет будет полезен), не объясните, почему он действует как таковой? Проводка кода сейчас. – Xerunix

+0

Я бы не послал волшебную нить, но заранее, если вы это знаете. И вы должны рассматривать tcp как поток, а не как пакеты (т. Е. На входе могут быть разные куски, чем полученные чтения). – eckes

ответ

1

Если ожидается, что чтение будет заполнить буфер, или получить именно то, что был послан один write() одноранговой, то ваше ожидание, что виноват здесь, не read(). не указано в передача более одного байта за раз, и нет гарантии сохранения границ записи.

Совершенно невозможно написать правильный код, не сохраняя результат read() в переменную.

+0

На самом деле я видел даже 0 возвратов от чтения. – eckes

+0

@Eckes Только при нулевой длине. Невозможно иначе, поскольку базовый 'recv()' тоже не сделает этого. – EJP

+0

hm, вероятно, я не помню ситуации, когда мне приходилось обрабатывать 0. (Однако определение POSIX read() явно определяет 0 байтовых чтений (по крайней мере, по STREAMS): [«Как read() обрабатывает сообщения с нулевым байтом STREAMS определяется текущим режимом режима чтения ... "] (http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html). (В Java вы не можете их отправить.) – eckes

0

Когда вы читаете InputStream, вы даете ему массив байтов для записи (и, возможно, смещение и максимальное количество для чтения). InputStream не гарантирует, что массив будет заполнен новыми данными. Возвращаемое значение - это количество байтов, которое было фактически прочитано в нем.

Что происходит в вашем примере это:

  • Первый пакет TCP приходит с "fileName\r\n" будет записано в ваш буфер, весь штраф до сих пор.
  • Вы снова вызываете read(), но следующий пакет еще не прибыл. read() вернется 0, потому что он не хотел блокировать пока данные не прибыли. Таким образом, буфер по-прежнему содержит "fileName\r\n". Изменить: как указано, read() всегда блокирует до тех пор, пока не прочитает хотя бы один байт. Не знаю, почему буфер не изменился.
  • На третьем прочитано, что контент прибыл.
  • Первый бит содержимого перезаписывается второй частью сообщения, последний бит по-прежнему содержит часть старого сообщения (я думаю, это то, что вы имели в виду).
  • и т.д., вы получите идею

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

+0

'InputStream.read()' блокирует, пока не будет доступен хотя бы один байт, или конец потока или исключение. Единственный способ, которым он может вернуть ноль, - это указать нулевую длину для чтения. обратный нуль, если данных нет. Только чтение неблокирующего канала может сделать это. – EJP

+0

На lea st в другой java он мог бы возвращать 0 байтов (особенно когда отправитель отправлял сегменты размером 0 байт). Я знаю, что он изменился в документации, но я не буду зависеть от него (фактически, когда вы обрабатываете частичные чтения, вы также можете обрабатывать 0 просмотров). – eckes

+0

@eckes Нет, не может. Вы ошибаетесь. Он не изменился в документации, которую я читал с 1997 года, и в старых версиях Java она не отличалась. – EJP

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