Отправлять и получать объект сериализации по UDP

Я пытаюсь отправить сериализованный объект из процесса сервера в клиентский процесс на Java с использованием UDP. Проблема в том, что клиент блокируется методом приема. Может кто-нибудь помочь?!

вот серверный код для отправки объекта:

  ClientModel C1= new ClientModel(100,"Noor","Noor",38,38,"asd");
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  ObjectOutputStream oos = new ObjectOutputStream(baos);
  oos.writeObject(C1);
  oos.flush();
  byte[] Buf= baos.toByteArray();
  packet = new DatagramPacket(Buf, Buf.length, client, port);
  socket.send(packet);

и вот клиентский код для получения объекта:

byte[] buffer = new byte[100000];
packet = new DatagramPacket(buffer, buffer.length );
socket.receive(packet);
System.out.println("packet received");

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

Ответ 1

Я не знаю, чего вы хотите достичь в конце, но работать с UDP не так просто... Основная причина заключается в описании объекта DatagramPacket:

Пакеты дейтаграмм используются для реализации доставка пакетов без установления соединения оказание услуг. Каждое сообщение направляется из одна машина к другой, основанная исключительно информации, содержащейся в пакет. Несколько пакетов, отправленных с одна машина к другой может быть маршрутизирована по-разному, и может заказ. Доставка пакетов не гарантируется.

Хороший учебник при работе с udp http://download.oracle.com/javase/tutorial/networking/datagrams/clientServer.html

О вашей блокировке:

Получает пакет датаграммы из этого разъем. Когда этот метод вернется, Буфер DatagramPacket заполняется полученные данные. Пакет датаграмм также содержит IP-адрес отправителя, и номер порта на отправителе машина.

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

Я действительно не тестировал его, но я уверен - на основе описания - что функция datagramsocket.reseive будет блокироваться до тех пор, пока пакет не будет заполнен (в вашем случае до получения 100 000 байтов).

Я предлагаю вам начать с datagrampacket с фиксированной известной длиной, где вы передаете размер фактической полезной нагрузки. Что-то вроде:

public static void main(String[] args) {
    ClientModel c1 = new ClientModel ();
    c1.data = 123;
    c1.name = "test";

    try {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(baos);
      oos.writeObject(c1);
      oos.flush();
      // get the byte array of the object
      byte[] Buf= baos.toByteArray();

      int number = Buf.length;;
      byte[] data = new byte[4];

      // int -> byte[]
      for (int i = 0; i < 4; ++i) {
          int shift = i << 3; // i * 8
          data[3-i] = (byte)((number & (0xff << shift)) >>> shift);
      }

      DatagramSocket socket = new DatagramSocket(1233);
      InetAddress client = InetAddress.getByName("localhost");
      DatagramPacket packet = new DatagramPacket(data, 4, client, 1234);
      socket.send(packet);

      // now send the payload
      packet = new DatagramPacket(Buf, Buf.length, client, 1234);
      socket.send(packet);

      System.out.println("DONE SENDING");
    } catch(Exception e) {
        e.printStackTrace();
    }
}

С другой стороны вы теперь ЗНАЕТЕ ваши размеры:

public static void main(String[] args) {
    try {
      DatagramSocket socket = new DatagramSocket(1234);

      byte[] data = new byte[4];
      DatagramPacket packet = new DatagramPacket(data, data.length );
      socket.receive(packet);

      int len = 0;
      // byte[] -> int
      for (int i = 0; i < 4; ++i) {
          len |= (data[3-i] & 0xff) << (i << 3);
      }

      // now we know the length of the payload
      byte[] buffer = new byte[len];
      packet = new DatagramPacket(buffer, buffer.length );
      socket.receive(packet);

        ByteArrayInputStream baos = new ByteArrayInputStream(buffer);
      ObjectInputStream oos = new ObjectInputStream(baos);
      ClientModel c1 = (ClientModel)oos.readObject();
      c1.print();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

CientModel clas sI используется:

public class ClientModel implements Serializable{
    private static final long serialVersionUID = -4507489610617393544L;

    String name = "";
    int data = 1;

    void print() {
        System.out.println(data +": " + name);
    }
}

Я тестировал этот код, и он работает отлично. Надеюсь, что это поможет (я получил byte-to-int и вокруг от http://www.tutorials.de/java/228129-konvertierung-von-integer-byte-array.html)

Изменить: Как указано в комментариях, часто очень плохо использовать UDP, в основном, потому что вы не знаете, получены ли ваши пакеты в правильном порядке или даже вообще. UDP НЕ гарантирует это. Я не делал слишком много udp-программирования, но единственной частью, на которую вы можете положиться (если я правильно понял), является то, что если вы получите пакет и он вписывается в дейтаграмму (65 527 байт - см. https://en.wikipedia.org/wiki/User_Datagram_Protocol), он будет содержать все это. Поэтому, если вам не нужен порядок, в котором приходит сообщение, и ваш объект вставляется в дейтаграмму, вы должны быть в порядке.

Edit2: Что касается кода: не используйте его как есть. это всего лишь пример, ind UDP, у вас должен быть только один тип пакета, и это с известным размером. таким образом вам не нужно отправлять "размер". Если вы используете код, как показано выше, и один пакет отбрасывается, следующий пакет будет неправильным размером (т.е. Первый пакет будет удален, внезапно вы будете проверять первые байты полезной нагрузки, чтобы получить размер).

Ответ 2

Я действительно не тестировал его, но я уверен, что на основе описание - что функция datagramsocket.reseive блокирует пока пакет не будет заполнен (в вашем случае до 100000 байт получено).

Это неправильно. Функция приема будет блокироваться до получения дейтаграммы, которая может быть меньше размера буфера (и обычно будет). Метод packet.getLength() скажет вам, насколько он был большой.