在UDP上发送和接收序列化对象

时间:2010-10-22 13:53:10

标签: java serialization udp

我正在尝试使用UDP将服务器进程中的序列化对象发送到Java中的客户端进程。问题是客户端在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 个答案:

答案 0 :(得分:13)

我最后不知道你想要完成什么,但使用UDP并不那么容易......主要原因在于DatagramPacket对象的描述:

  

数据报包用于实现   无连接数据包传递   服务。每条消息都来自   一台机器到另一台机器   关于其中包含的信息   包。从中发送多个数据包   一台机器到另一台机器可能会被路由   不同的,可能会到达任何   订购。数据包传递不是   保证。

使用udp时的一个很好的教程是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:

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

    String name = "";
    int data = 1;

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

我测试了这段代码,它运行得很好。希望有所帮助(我从http://www.tutorials.de/java/228129-konvertierung-von-integer-byte-array.html得到了byte-To-int和around)

编辑:正如评论中所述,主要使用UDP通常是一个非常糟糕的主意,因为您不知道您的数据包是以正确的顺序接收,还是根本不知道。 UDP不保证。我没有做太多的udp编程,但你可以依赖的唯一部分(如果我理解正确)是,如果你得到一个数据包并且它适合数据报(65,527字节 - 见https://en.wikipedia.org/wiki/User_Datagram_Protocol)它将包含整个事物。因此,如果您不关心消息的来源以及您的对象是否适合数据报,那么您应该没问题。

Edit2:至于代码:不要按原样使用它。它只是一个例子,在UDP中你应该只有一种类型的数据包,而且这个数据包已知。那样你就不需要发送“大小”了。如果您使用上面显示的代码,并且丢弃了一个数据包,则下一个数据包将是错误的大小(即第一个数据包被丢弃,突然您正在检查有效负载的第一个字节以获得大小)。

答案 1 :(得分:1)

  

我没有真正测试它,但我很确定 - 基于   description - datagramsocket.reseive函数将阻塞   直到数据包被填满(在你的情况下,直到100000字节为止)   接收到的)。

这是错误的。接收函数将一直阻塞,直到收到一个数据报,该数据报可能小于缓冲区大小(通常是)。 packet.getLength()方法会告诉你它有多大。