转载请注明来源
目录
方法一:使用getLength()截取更新的数据部分。下图中,使用substring(0,p.getLength())截取了p.getData()中被更新的数据部分。
方法二:每次接收数据开始前,对DatagramPacket的数据进行置零。下图中,从第一次开始,都对DatagramPacket前getLength()个字节的数据进行置零。
问题说明
DatagramPacket的两个方法getData()和getLength()是不对应的。getLength()反映了刚刚接收到的数据的长度,而getData()反映了DatagramPacket对应缓冲区中的新接收到的数据和未被覆盖的旧数据,当我们使用DatagramPacket来处理新接收到的数据时,就容易同时触及到旧数据导致混乱。下图所示,udp客户端Client A第一次收到了数据“welcome",getData()获得的数据是”welcome",getLength()的结果是7;ClientA第二次收到了数据“hi",getData()获得的数据是”hilcome",其保留了旧数据“welcome"未被覆盖的部分”lcome",而getLength()的结果是2,即“hi"的长度。

这里给出两种解决方法
方法一:使用getLength()截取更新的数据部分。下图中,使用substring(0,p.getLength())截取了p.getData()中被更新的数据部分。

方法二:每次接收数据开始前,对DatagramPacket的数据进行置零。下图中,从第一次开始,都对DatagramPacket前getLength()个字节的数据进行置零。

总结
方法一和方法二都能得到正确结果,但是方法二对缓冲区buf进行了直接操作,很容易发生数组元素访问越界的错误。在DatagramPacket 被receive时,缓冲区buf的length不变,DatagramPacket允许接收的最大字节数也不变;而getLength()的结果发生变化;新数据只是在缓冲区中从偏移量开始覆盖旧数据,如果旧数据长度更大,则保留部分旧数据。
建议使用方法一
附测试代码
package udp_test1.udp_client;
//library
import java.io.*;
import java.net.*;
import java.util.Scanner;
class Recv_Thread extends Thread{
private byte [] buf;
private DatagramSocket ds = null;
private DatagramPacket p = null;
public Recv_Thread(int buf_len, DatagramSocket ds) {
buf = new byte[buf_len];
this.ds = ds;
p = new DatagramPacket(buf,250);
}
@Override
public void run() {
while(true) {
try {
ds.receive(p);
String str = new String(p.getData()).substring(0,p.getLength());
System.out.println("来自["+p.getPort()+"]的数据:"+str);
}catch(Exception e ) {
e.printStackTrace();
}
}
}
}
class Send_Thread extends Thread{
private DatagramSocket ds = null;
private InetAddress des_address = null;
private int des_port;
Scanner s = new Scanner(System.in);
Send_Thread(DatagramSocket ds, InetAddress des_address,int des_port){
this.ds = ds;
this.des_address = des_address;
this.des_port = des_port;
}
@Override
public void run() {
while(true) {
try {
byte[] buf = s.nextLine().getBytes();
DatagramPacket p = new DatagramPacket(buf,buf.length,des_address,des_port);
ds.send(p);
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
public class Udp_Client extends Thread{
private DatagramSocket ds = null;
private InetAddress des_address = null;
private int des_port = 0;
private int buf_len = 256;
private Send_Thread st = null;
private Recv_Thread rt = null;
public Udp_Client(int src_port,int des_port, InetAddress des_address) {
this.des_port = des_port;
this.des_address = des_address;
try{
ds = new DatagramSocket(src_port);
System.out.println("本地开启UDP "+src_port+" 端口");
}catch(IOException e ) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
st = new Send_Thread(ds,des_address,des_port);
st.start();
rt = new Recv_Thread(buf_len,ds);
rt.start();
st.join();
rt.join();
}catch(Exception e) {
e.printStackTrace();
}
ds.close();
}
}
博客指出DatagramPacket的getData()和getLength()方法不对应,使用其处理新数据易触及旧数据致混乱。给出两种解决方法,一是用getLength()截取更新数据,二是接收数据前对DatagramPacket数据置零。建议使用第一种方法,还附了测试代码。
4万+





