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

我只想接收能够重建的对象但我无法接收数据包本身。

我不知道你最终想要完成什么,但使用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中你应该只有一种类型的数据包,而且这个数据包已知。 这样你就不需要发送“大小”了。 如果您使用上面显示的代码,并且丢弃了一个数据包,则下一个数据包将是错误的大小(即第一个数据包被丢弃,突然您正在检查有效负载的第一个字节以获得大小)。

我没有真正测试它,但我很确定 – 根据描述 – datagramsocket.reseive函数将阻塞,直到数据包被填满(在你的情况下,直到收到100000字节)。

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