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

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

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

  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");

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

2 ответов


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

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

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

о блокировка:

получает пакет дейтаграммы от этого разъем. Когда этот метод возвращается, Создает буфер заполнен полученные данные. В пакет дейтаграммы также содержит IP-адрес отправителя , и номер порта отправителя машина.

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

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

Я бы предложил вам начать с 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)

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

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


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

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