2010-10-22 2 views
10

Я пытаюсь отправить сериализованный объект из процесса сервера в клиентский процесс на Java с использованием UDP. Проблема в том, что клиент блокируется методом приема. Может кто-нибудь помочь ?!Отправить и получить объект serialize в 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"); 

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

+0

Возможно, вам нужно сбросить буфер ... – ultrajohn

ответ

13

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

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

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

Об блокированию:

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

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

я действительно не проверить это, но я уверен, - на основе описания - что 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 Ši используется:

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

+0

Я тоже не тестировался, но из описания C recvfrom (2) видно, что чтение из UDP-соединения может возвращаться, как только целая датаграмма будет считана и фактическое число (в случае JDK оно будет в поле DatagramPacket.length). Я предлагаю написать простой Java echo client/server для проверки поведения. –

+0

Дейтаграммы могут выходить из строя или вообще никогда. Возможно, вам придется подтвердить начальный пакет, чтобы подтвердить следующий ожидаемый размер, а затем получить пакет полезной нагрузки – user12345613

+0

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

1

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

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

Смежные вопросы