How to reinitialize the buffer of a packet?(如何重新初始化数据包的缓冲区?)
问题描述
I am having some problem while I am sending UDP packets from netcat or my client to my UDP server which listens for broadcast UDP packets. The problem is that I can't reinitilize the buffer of socket.receive(packet);
And as you check my console output you will see that the packets are sent or received twice or even more times and most annoying of all is that when I send a packet with greater length first, the next one which is smaller consists part of the previous! (Problems are marked with HERE on the console output) My Client and Server are located on the same LAN.
Client code:
DatagramSocket socket = new DatagramSocket();
socket.setBroadcast(true);
byte[] buf = ("Hello from Client").getBytes();
byte[] buf2 = ("omg").getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, getBroadcastAddress(UDPConnection.context), Server.SERVERPORT);
DatagramPacket packet2 = new DatagramPacket(buf2, buf2.length, getBroadcastAddress(UDPConnection.context), Server.SERVERPORT);
Log.d("UDP", "C: Sending: '" + new String(buf) + "'");
socket.send(packet);
socket.send(packet2);
Server code:
void run(){
MulticastSocket socket = new MulticastSocket(SERVERPORT);
socket.setBroadcast(true);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while(true){
Log.d("UDP", "S: Receiving...");
socket.receive(packet);
//socket.setReceiveBufferSize(buf.length);
packet.setData(buf);
Log.i("BUFFER_packet",packet.getLength()+"");
Log.i("BUFFER_socket",socket.getReceiveBufferSize()+"");
Log.d("UDP", "S: From: " + packet.getAddress().getHostAddress());
Log.d("UDP", "S: Received: "+getRidOfAnnoyingChar(packet));
Log.d("UDP", "S: Done.");
}
}
//this method is getting rid of the "questionmark in a black diamond" character
public String getRidOfAnnoyingChar(DatagramPacket packet){
Log.i("UDP","Inside getridofannoyingchar method.");
String result = new String(packet.getData());
char[] annoyingchar = new char[1];
char[] charresult = result.toCharArray();
result = "";
for(int i=0;i<charresult.length;i++){
if(charresult[i]==annoyingchar[0]){
break;
}
result+=charresult[i];
}
return result;
}
Console:
11-27 18:15:27.515: D/UDP(15242): S: Connecting...
11-27 18:15:27.519: I/ServerIP(15242): ::
11-27 18:15:27.519: I/LocalIP(15242): 192.168.0.4
11-27 18:15:27.523: D/UDP(15242): S: Receiving...
11-27 18:15:28.031: D/UDP(15242): C: Connecting...
11-27 18:15:28.039: I/BroadcastIP(15242): 192.168.0.255
11-27 18:15:28.042: I/BroadcastIP(15242): 192.168.0.255
11-27 18:15:28.070: D/UDP(15242): C: Sending: 'Hello from Client'
11-27 18:15:28.074: I/BUFFER_packet(15242): 1024
11-27 18:15:28.074: I/BUFFER_socket(15242): 110592
11-27 18:15:28.074: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.074: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.078: I/BUFFER_packet(15242): 1024
11-27 18:15:28.078: I/BUFFER_socket(15242): 110592
11-27 18:15:28.078: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.078: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.085: D/UDP(15242): S: Received: Hello from Client <------------HERE
11-27 18:15:28.085: D/UDP(15242): S: Done.
11-27 18:15:28.085: D/UDP(15242): S: Receiving...
11-27 18:15:28.085: D/UDP(15242): S: Received: Hello from Client <------------HERE
11-27 18:15:28.085: D/UDP(15242): S: Done.
11-27 18:15:28.085: D/UDP(15242): S: Receiving...
11-27 18:15:28.085: I/BUFFER_packet(15242): 1024
11-27 18:15:28.085: I/BUFFER_socket(15242): 110592
11-27 18:15:28.085: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.085: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.089: D/UDP(15242): S: Received: omglo from Client <------------HERE
11-27 18:15:28.089: D/UDP(15242): S: Done.
11-27 18:15:28.089: D/UDP(15242): S: Receiving...
11-27 18:15:28.089: I/BUFFER_packet(15242): 1024
11-27 18:15:28.089: I/BUFFER_socket(15242): 110592
11-27 18:15:28.089: D/UDP(15242): S: From: 192.168.0.4
11-27 18:15:28.089: I/UDP(15242): Inside getridofannoyingchar method.
11-27 18:15:28.089: D/UDP(15242): S: Received: omglo from Client <------------HERE
11-27 18:15:28.089: D/UDP(15242): S: Done.
11-27 18:15:28.089: D/UDP(15242): S: Receiving...
11-27 18:15:28.089: D/UDP(15242): C: Sent.
11-27 18:15:28.089: D/UDP(15242): C: Done.
Any help will be highly appreciated! :)
PS. there might be some outputs in the console like Done/Sent/Connecting/Receiving that are not added to my sample code but all the Received:/BUFFER_packet/_socket/From are present.
you don't need to reinitialize the buffer in the packet, you just need to reset the contents of the buffer to whatever they were initially (i.e. you need to fill the receiving array with zeroes).
A call of:
Arrays.fill(buf,(byte)0);
on the server side will reset the array to zeroes since arrays in Java are pass-by-reference not pass-by-value (i.e. the reference you have to the array contents is the same as the reference that the DatagramPacket has, so you can modify it without going through DatagramPacket methods).
Having said that the way you are serialising/deserialising the data isn't ideal. You would be better off using a ByteArrayOutputStream and ByteArrayInputStream wrapped around the sending and receiving buffers, and then a DataOutputStream / DataInputStream wrapped around those. These would allow you to write and read the string in a well defined format which would likely store the length of the string so that any remaining data on the buffer would be ignored anyway. Properly serialising / deserialising in this way would also remove the need to strip the 'black diamond' character.
DataOutputStream.writeUTF
If you're interested in the reasoning behind this it is to do with your use of java.lang.String's default serialisation (getBytes() and new String(byte[])) and how the UDP packet is being populated. I'll try and boil it down to the crucial bits:
Java's internal representation for String objects is not a byte array - its a char array. Java chars are not the same as bytes - one char is actually 2 bytes because it needs to be able to represent more than just the latin alphabet (acbd...), it needs to support other characters from other languages/cultures like stuff from Cyrillic, Kanji etc and one byte isn't enough (one byte gets you 256 possibilities, 2 bytes gets you 65536 possibilities).
As a result when you call getBytes() Java has to use some 'scheme' (encoding) to turn that character array into a byte array (serialisation). The details of that don't matter too much, but when you send the first chunk of bytes, (lets say its 10 bytes long) you read the packet into a much bigger buffer (1024 bytes). Then you ask Java String to deserialise that entire buffer, not just the 10 bytes.
The scheme (encoding) doesn't know to only deal with the first 10 bytes so it tries to decode the whole 1024 bytes, and then you get weird characters on your string like the black diamond, or (where you've put some other data after the 10 bytes by sending 'hello') you get characters from the previous receive mixed into your string.
Using write/readUTF will write the length of the byte array as well as the data, so when you read it again it will know it only has to read the first 10 characters (or however many are valid).
这篇关于如何重新初始化数据包的缓冲区?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何重新初始化数据包的缓冲区?
基础教程推荐
- 如何在不安装整个 WTP 包的情况下将 Tomcat 8 添加到 Eclipse Kepler 2022-01-01
- 如何使用 Eclipse 检查调试符号状态? 2022-01-01
- 如何对 HashSet 进行排序? 2022-01-01
- Spring Boot Freemarker从2.2.0升级失败 2022-01-01
- 首次使用 Hadoop,MapReduce Job 不运行 Reduce Phase 2022-01-01
- 如何强制对超级方法进行多态调用? 2022-01-01
- 如何使用 Stream 在集合中拆分奇数和偶数以及两者的总和 2022-01-01
- 在螺旋中写一个字符串 2022-01-01
- 由于对所需库 rt.jar 的限制,对类的访问限制? 2022-01-01
- Java 中保存最后 N 个元素的大小受限队列 2022-01-01