Недостающие байты в передаче файлов TCP - PullRequest
3 голосов
/ 03 декабря 2011

Мне нужно иметь возможность читать файл, разбивать его на пакеты произвольного размера, скажем, 512 байт, и отправлять эти пакеты по TCP. Проблема в том, что получатель не получает все байты, которые я отправляю. Если я отправляю 1000 пакетов, получатель блокируется при чтении из InputStream, потому что у него больше нет данных для чтения около 990 пакетов или около того.

Вот код (только отправляющая и получающая части):

Отправитель:

int parts = (int)Math.ceil((double)(file.length()/512.0));

out.println(parts+"");
int readFile;
int i = 0;
while ((readFile = fileIn.read(buffer)) != -1) {
   i++;
   fileOut.write(buffer, 0, readFile);
   fileOut.flush();
   System.out.println("-- Sent packet " + i + "/" + parts + ". " + "Bytes sent = " + readFile);
}

Получатель:

int parts = Integer.parseInt(in.readLine());
byte[] buffer = new byte[512];
FileOutputStream pw = new FileOutputStream("file.ext");
DataInputStream fileIn = new DataInputStream(socket.getInputStream());
for(int j = 0; j < parts; j++){
   int read = 0;
   if(j == parts - 1){
      read = fileIn.read(buffer);
      pw.write(buffer, 0, read);
   }else{
      fileIn.readFully(buffer);
      pw.write(buffer);
   }
   System.out.println("-- Received packet " + (j+1) + "/" + parts + ". Read " +read+ " bytes.");
}

Я попытался увеличить размер буфера отправки и получения сокета, но безуспешно. Чего мне не хватает?

Вот пример выходных данных:

Отправитель:

-- Sent packet 1/10. Bytes sent = 512
-- Sent packet 2/10. Bytes sent = 512
-- Sent packet 3/10. Bytes sent = 512
-- Sent packet 4/10. Bytes sent = 512
-- Sent packet 5/10. Bytes sent = 512
-- Sent packet 6/10. Bytes sent = 512
-- Sent packet 7/10. Bytes sent = 512
-- Sent packet 8/10. Bytes sent = 512
-- Sent packet 9/10. Bytes sent = 512
-- Sent packet 10/10. Bytes sent = 234

Получатель:

-- Received packet 1/10. Read 512 bytes.
-- Received packet 2/10. Read 512 bytes.
-- Received packet 3/10. Read 512 bytes.
-- Received packet 4/10. Read 512 bytes.
-- Received packet 5/10. Read 512 bytes.
-- Received packet 6/10. Read 512 bytes.
-- Received packet 7/10. Read 512 bytes. (And it blocks here, because there is no more data to read)

Ответы [ 2 ]

3 голосов
/ 03 декабря 2011

TCP - это потоковый протокол . Пакетов нет, только один поток данных.

Вы не должны предполагать, что один write() (с или без flush()) будет соответствовать одному read(). Поэтому ваш цикл приема for(int j = 0; j < parts; j++) введен в заблуждение: лучшим подходом будет подсчет количества байтов чтения и подготовка к вызовам read(), возвращающим различные объемы данных.

В комментариях вы утверждаете, что readFully() решает проблему. Однако мое беспокойство связано не столько с кодом, сколько с пакетным представлением потока. Это приводит к таким ошибкам в вашем последнем вызове fileIn.read(buffer). Он может вернуть половину данных, которые были отправлены как часть вашего последнего «пакета», и вы никогда не узнаете!

1 голос
/ 04 декабря 2011

разбить его на пакеты произвольного размера

Почему? Это потоковый протокол. Вы можете разбить его столько, сколько захотите на отправляющем конце, но локальный TCP сделает все возможное, чтобы объединить ваши записи в более крупные сегменты TCP; локальный IP будет затем разделен на IP-пакеты размером с MTU; промежуточные маршрутизаторы могут фрагментировать это дальше; удаленный IP затем соберет фрагменты в пакеты; удаленный TCP затем соберет пакеты в сегменты; и тогда удаленное приложение будет получать порциями в зависимости от всего этого, а также от размера буфера приема сокета в ядре и от размера буфера приема приложения.

Не пытайтесь обдумать всю эту обработку. Ты не можешь Просто напишите, что вы должны написать, когда у вас есть, что написать.

Если у вас есть «пропущенные байты», это может быть только потому, что вы игнорируете значение длины, возвращаемое read () в получателе, или если вы используете неблокирующий ввод / вывод в отправителе, значение длины, возвращаемое написать () в отправителя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...