javaUDP協(xié)議DatagramPacket、DatagramSocket
/**
* UDP協(xié)議,TCP/IP協(xié)議族中的協(xié)議,面向無連接,通信不需要建立連接(三次握手四次揮手),可能發(fā)生丟包亂序錯(cuò)包重復(fù)包,效率高于TCP,常用于游戲和視頻通話
*/
public class DatagramPacket1 {
? ?public static void main(String[] args) {
? ? ? ?//UDP同樣需要先創(chuàng)建服務(wù)端/接收方
? ? ? ?DatagramSocket ds = null;
? ? ? ?try {
? ? ? ? ? ?DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
? ? ? ? ? ?//datagram數(shù)據(jù)報(bào)packet包,UDP使用數(shù)據(jù)報(bào)包封裝數(shù)據(jù),發(fā)送方發(fā)送數(shù)據(jù)報(bào)包,接收方接收數(shù)據(jù)報(bào)包
? ? ? ? ? ?//服務(wù)端/接收方的數(shù)據(jù)報(bào)包對(duì)象的構(gòu)造器需要:用于存放接收到的數(shù)據(jù)的字節(jié)數(shù)組byte[]、字節(jié)數(shù)組的可用長度(還可以指定存放的起始位置offset,不寫默認(rèn)從0位開始)
? ? ? ? ? ?ds = new DatagramSocket(9999);
? ? ? ? ? ?//通過DatagramSocket類發(fā)送/接收數(shù)據(jù)報(bào)包,需要指定端口用于發(fā)送/接收
? ? ? ? ? ?ds.receive(dp);
? ? ? ? ? ?//.receive(DatagramPacket)阻塞,等待接收數(shù)據(jù),將收到的數(shù)據(jù)放入準(zhǔn)備好的接收用數(shù)據(jù)報(bào)包中
? ? ? ? ? ?System.out.println(new String(dp.getData(),dp.getOffset(),dp.getLength()));
? ? ? ? ? ?//.getData()返回?cái)?shù)據(jù)報(bào)包中的字節(jié)數(shù)據(jù),new String(byte[])將數(shù)據(jù)轉(zhuǎn)為字符串,因?yàn)閿?shù)組可能沒有放滿,所以需要指定長度
? ? ? ? ? ?//.getOffset()返回?cái)?shù)據(jù)開始位置 .getLength()返回?cái)?shù)據(jù)實(shí)際長度
? ? ? ?} catch (IOException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?} finally {
? ? ? ? ? ?if (ds != null) {
? ? ? ? ? ? ? ?ds.close();
? ? ? ? ? ? ? ?//DatagramSocket使用端口,用完需要關(guān)閉通道
? ? ? ? ? ?}
? ? ? ?}
? ?}
}
class UDPClient{
? ?public static void main(String[] args) {
? ? ? ?//通過客戶端/發(fā)送方發(fā)送數(shù)據(jù)
? ? ? ?byte[] data = "將需要發(fā)送的數(shù)據(jù)轉(zhuǎn)換為字節(jié)數(shù)組".getBytes();
? ? ? ?DatagramPacket dp = null;
? ? ? ?try {
? ? ? ? ? ?dp = new DatagramPacket(data,0,data.length,InetAddress.getLocalHost(),9999);
? ? ? ? ? ?//客戶端/發(fā)送方構(gòu)造器需要:存放了要發(fā)送的數(shù)據(jù)的字節(jié)數(shù)組、數(shù)據(jù)起始位置offset(不寫默認(rèn)從0位開始)、數(shù)據(jù)實(shí)際長度、用于指定發(fā)送地址IP:port的SocketAddress抽象類(子類為InetSocketAddress)(也可以用InetAddress指定ip,再加int port指定端口)
? ? ? ? ? ?//接收方不需要指定地址,發(fā)送方需要指定地址
? ? ? ? ? ?try(DatagramSocket ds = new DatagramSocket(8888)) {
? ? ? ? ? ? ? ?//與TCP不同的是,UDP發(fā)送方和接收方使用同一個(gè)類DatagramSocket,因?yàn)椴恍枰⑦B接,所以從一開始雙方即為平等的,既可以發(fā)也可以接,也可以通過數(shù)據(jù)報(bào)包指定不同的地址群發(fā)
? ? ? ? ? ? ? ?//這里是客戶端/發(fā)送方使用8888端口向 本機(jī)地址:9999端口發(fā)送數(shù)據(jù)報(bào)包
? ? ? ? ? ? ? ?ds.send(dp);
? ? ? ? ? ? ? ?/*
? ? ? ? ? ? ? ?ByteArrayOutputStream baos = new ByteArrayOutputStream();
? ? ? ? ? ? ? ?DataOutputStream dos = new DataOutputStream(baos);
? ? ? ? ? ? ? ? ?發(fā)送基本數(shù)據(jù)類型,先將基本數(shù)據(jù)寫入數(shù)組,再將數(shù)組封包,發(fā)送
? ? ? ? ? ? ? ?dos.writeLong(1000L);
? ? ? ? ? ? ? ?dos.writeChar('a');
? ? ? ? ? ? ? ?dos.writeUTF("接收方也需要按寫入的順序讀取各個(gè)數(shù)據(jù)類型");
? ? ? ? ? ? ? ?dos.flush();
? ? ? ? ? ? ? ?byte[] data2 = baos.toByteArray();
? ? ? ? ? ? ? ?ds.send(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發(fā)送對(duì)象,要發(fā)送的對(duì)象必須實(shí)現(xiàn)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 SendObject{
? ?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.send(dp);
? ? ? ?} catch (IOException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?}
? ? ? ?//接收方也需要有這個(gè)類才能使用ObjectInputStream正確讀取
? ?}
}