/**
* UDP协议,TCP/IP协议族中的协议,面向无连接,通信不需要建立连接(三次握手四次挥手),可能发生丢包乱序错包重复包,效率高于TCP,常用于游戏和视频通话
*/
public class DatagramPacket1 {
public static void main(String[] args) {
//UDP同样需要先创建服务端/接收方
DatagramSocket ds = null;
try {
DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
//datagram数据报packet包,UDP使用数据报包封装数据,发送方发送数据报包,接收方接收数据报包
//服务端/接收方的数据报包对象的构造器需要:用于存放接收到的数据的字节数组byte[]、字节数组的可用长度(还可以指定存放的起始位置offset,不写默认从0位开始)
ds = new DatagramSocket(9999);
//通过DatagramSocket类发送/接收数据报包,需要指定端口用于发送/接收
ds.receive(dp);
//.receive(DatagramPacket)阻塞,等待接收数据,将收到的数据放入准备好的接收用数据报包中
System.out.println(new String(dp.getData(),dp.getOffset(),dp.getLength()));
//.getData()返回数据报包中的字节数据,new String(byte[])将数据转为字符串,因为数组可能没有放满,所以需要指定长度
//.getOffset()返回数据开始位置 .getLength()返回数据实际长度
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (ds != null) {
ds.close();
//DatagramSocket使用端口,用完需要关闭通道
}
}
}
}
class UDPClient{
public static void main(String[] args) {
//通过客户端/发送方发送数据
byte[] data = "将需要发送的数据转换为字节数组".getBytes();
DatagramPacket dp = null;
try {
dp = new DatagramPacket(data,0,data.length,InetAddress.getLocalHost(),9999);
//客户端/发送方构造器需要:存放了要发送的数据的字节数组、数据起始位置offset(不写默认从0位开始)、数据实际长度、用于指定发送地址IP:port的SocketAddress抽象类(子类为InetSocketAddress)(也可以用InetAddress指定ip,再加int port指定端口)
//接收方不需要指定地址,发送方需要指定地址
try(DatagramSocket ds = new DatagramSocket(8888)) {
//与TCP不同的是,UDP发送方和接收方使用同一个类DatagramSocket,因为不需要建立连接,所以从一开始双方即为平等的,既可以发也可以接,也可以通过数据报包指定不同的地址群发
//这里是客户端/发送方使用8888端口向 本机地址:9999端口发送数据报包
ds.s(dp);
/*
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
发送基本数据类型,先将基本数据写入数组,再将数组封包,发送
dos.writeLong(1000L);
dos.writeChar('a');
dos.writeUTF("接收方也需要按写入的顺序读取各个数据类型");
dos.flush();
byte[] data2 = baos.toByteArray();
ds.s(new DatagramPacket(data2,data2.length,new InetSocketAddress("127.0.0.1",9999)));
*/
} catch (IOException e) {
throw new RuntimeException(e);
}
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}
class Person implements Serializable{
//使用UDP发送对象,要发送的对象必须实现Serializable接口
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class SObject{
public static void main(String[] args) {
Person p = new Person("qian",20);
byte[] obj = null;
try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(p);
oos.flush();
obj = baos.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
DatagramPacket dp = new DatagramPacket(obj,obj.length,new InetSocketAddress("127.0.0.1",9999));
try(DatagramSocket ds = new DatagramSocket(8888)) {
ds.s(dp);
} catch (IOException e) {
throw new RuntimeException(e);
}
//接收方也需要有这个类才能使用ObjectInputStream正确读取
}
}