Проблема с сокетом Java: пакеты объединяются на стороне получателя - PullRequest
1 голос
/ 14 октября 2011

У меня проблема с сокетом.Эта проблема возникает, когда я запускаю сервер и клиент на одном компьютере, т.е. с помощью параметра «localhost».Но проблема не видна, когда используются разные ПК.Клиент отправляет файл с этими кодами:

output_local.write(buffer, 0, bytesRead);
output_local.flush();

И после этого другим способом я отправляю команду с такими:

outputStream.write(string);
outputStream.flush();

Сервер добавляет команду в конецфайл.Поэтому он думает, что еще не получил команду от клиента.у вас есть идея, что может вызвать эту проблему?Как я могу устранить дефект?ниже приведен метод получения файла на сервере:

    while (true) {
        try {
            bytesReceived = input.read(buffer);
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("exception occured");
            break;
        }
        System.out.println("received:" + bytesReceived);
        try {
            /* Write to the file */
            wr.write(buffer, 0, bytesReceived);
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
        total_byte = total_byte + bytesReceived;
        if (total_byte >= filesizeInt) {
            break;
        }
    }

Ответы [ 3 ]

7 голосов
/ 14 октября 2011

Если вам нужна поддержка сообщений, вам нужен протокол для уточнения того, что вы собираетесь отправлять и получать.

В TCP нельзя полагаться на получение отдельных «пакетов».отдельно (например, отправка 4 фрагментов по 10 байт может быть получена как 1 фрагмент из 40, или из 2 блоков из 20, или как один фрагмент из 39 и один фрагмент из 1).TCP гарантирует доставку заказа, но не какую-либо конкретную «упаковку» ваших данных.

Так, например, если вы отправляете строку, вам нужно сначала отправить длину строки, а затем ее байты.Логика в псевдокоде будет выглядеть примерно так:

Клиент:

  1. Отправить индикатор команды
  2. Отправить длину полезной нагрузки
  3. Отправить полезную нагрузку

Сервер:

  1. Считать индикатор команды
  2. Считать длину полезной нагрузки
  3. Цикл чтения полезной нагрузки, пока не будет считана полная длина
5 голосов
/ 14 октября 2011

Недостаток в том, что вы обрабатываете потоковый протокол (TCP), как если бы это был протокол, ориентированный на сообщения. Это не. Вы должны предположить , что это может произойти.

Если вам нужно разбить ваш поток на отдельные сообщения, вы должны использовать разделители или (предпочтительно IMO) префикс длины для каждого сообщения. Затем вы также должны ожидать, что любое прочитанное вами сообщение может не получить столько данных, сколько вы просили - иными словами, не только сообщения могут быть объединены, если вы не будете осторожны, но они могут легко быть разделенным.

Я упомянул, что я предпочитаю префикс длины перед разделителями. Плюсы и минусы:

  • Преимущество использования разделителя сообщений заключается в том, что вам не нужно знать размер сообщения перед началом отправки.
  • Преимущества использования префикса длины:
    • Код для чтения сообщения не должен заботиться о данных в сообщении вообще - ему нужно только знать, как долго это происходит. Вы читаете длину сообщения, вы читаете данные сообщения (циклично, пока не прочитаете все), а затем передаете сообщение для обработки. Простой.
    • Вам не нужно беспокоиться об «экранировании» разделителя, если вы хотите, чтобы он появлялся в обычном сообщении.
3 голосов
/ 14 октября 2011

Поскольку TCP является потоково-ориентированным соединением, это нормальное поведение, если записывающее устройство пишет быстрее, чем считывающее устройство, или стек TCP отправляет пакеты.

Вы должны добавить разделитель для разделения частей потоков, например, используя поле длины для подпакетов или используя разделители, такие как символ новой строки (\n, код символа 10).

Другим вариантом может быть использование UDP (или даже SCTP), но это зависит от задачи, которая должна быть выполнена.

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