Отправить и получить сериализованный объект по UDP - PullRequest
10 голосов
/ 22 октября 2010

Я пытаюсь отправить сериализованный объект из серверного процесса в клиентский процесс в 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");

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

Ответы [ 2 ]

13 голосов
/ 22 октября 2010

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

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

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

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

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

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

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

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

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: Что касается кода: не используйте его как есть. Это только пример, в UDP вы должны иметь только один тип пакета, и это с известным размером. таким образомвам не нужно отправлять «размер». Если вы используете код, как показано выше, и один пакет отброшен, следующий пакет будет неправильного размера (т. е. первый пакет отброшен, вдруг вы проверяете первый байтиз полезной нагрузки, чтобы получить размер).

1 голос
/ 06 марта 2014

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

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

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