赞
踩
目录
UDP(User Datagram Protocol)用户数据报协议,为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法。
DatagramSocket:该类表示用于发送/接收数据包的套接字
DatagramPacket:该类表示被传输的数据包
UDP编程可以概括为以下几步
发送端
接收端
发送端
- public class UdpSender {
- public static void main(String[] args) throws Exception {
- // 1、指定端口,创建发送端
- DatagramSocket client = new DatagramSocket(8888);
-
- // 2、准备数据,转成字节数组
- String str = "Hello World!你好";
- byte[] datas = str.getBytes();
-
- // 3、将字节数组封装成包,
- // 发送端构造方法传递 ——>
- // 数据字节数组,起始位置,长度,IP套接字地址(接收端的ip/主机 + 端口)
- DatagramPacket packet = new DatagramPacket(datas, 0, datas.length,
- new InetSocketAddress("localhost", 9999));
-
- // 4、发送数据
- client.send(packet);
-
- // 5、释放资源
- client.close();
- }
- }
接收端
- public class UdpReceiver {
- public static void main(String[] args) throws Exception {
- // 1、指定端口,创建接收端,此处的端口应对应发送端数据包传递的端口
- DatagramSocket server = new DatagramSocket(9999);
-
- // 2、准备容器,封装成DatagramPacket包
- byte[] contanier = new byte[60*1024]; // 60K
- // 接收端的数据包不用传递IP套接字地址
- DatagramPacket packet = new DatagramPacket(contanier, 0, contanier.length);
-
- // 3、阻塞式接收包,会一直等待数据包
- System.out.println("等待接收");
- server.receive(packet);
- System.out.println("接收到数据包,进行解析");
-
- // 4、解析包
- byte[] datas = packet.getData(); // 字节数组
- int len = packet.getLength(); // 长度
- System.out.println(new String(datas));
- System.out.println(len);
-
- // 5、释放资源
- server.close();
- }
- }
接收端控制台
与基本通信相同,唯一需要改动的部分就是发送端的数据转字节数组,接收端的字节数组转数据
发送端
- // 1、指定端口,创建发送端
-
- // 2、准备基本类型数据,转成字节数组
- // ByteArrayOutputStream 用于将数据转为字节数组
- // BufferedOutputStream 用于缓冲,提升效率
- // DataOutputStream 用于将基本类型数据写入输出流
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
-
- dos.writeInt(1);
- dos.writeChar('a');
- dos.writeBoolean(true);
- dos.writeFloat(1.2f);
- dos.flush(); // 调用flush()将缓冲区数据输出
-
- byte[] datas = baos.toByteArray();
-
- // 3、将字节数组封装成包
- // 4、发送数据
- // 5、释放资源
接收端
- // 1、指定端口,创建接收端
- // 2、准备容器,封装成DatagramPacket包
- // 3、阻塞式接收包
-
- // 4、解析基本类型
- // ByteArrayInputStream 获取传递过来的输入流
- // BufferedInputStream 用于缓冲提升效率
- // DataInputStream 用于读取输入流中的基本数据类型
- ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());
- DataInputStream dis = new DataInputStream(new BufferedInputStream(bais));
-
- // 取值顺序应和写入顺序一致
- System.out.println(dis.readInt());
- System.out.println(dis.readChar());
- System.out.println(dis.readBoolean());
- System.out.println(dis.readFloat());
-
- // 5、释放资源
接收端控制台
对象要能够被传输,必须实现Serializable接口,最好提供一个serialVersionUID
Person.java
- public class Person implements Serializable {
- private static final long serialVersionUID = -3201672726868875942L;
-
- private String name;
- private transient int age; // 使用transient修饰的属性不会被序列化传输
-
- public String getName() {
- return name;
- }
-
- // get/set/constructor方法省略
- }
发送端
- // 1、指定端口,创建发送端
-
- // 2、准备对象类型数据,转成字节数组
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(baos));
-
- oos.writeObject(new Person("IcyDate", 18));
- oos.flush();
-
- byte[] datas = baos.toByteArray();
-
- // 3、将字节数组封装成包
- // 4、发送数据
- // 5、释放资源
接收端
- // 1、指定端口,创建接收端,此处的端口应对应发送端发送数据指定的端口
- // 2、准备容器,封装成DatagramPacket包
- // 3、阻塞式接收包
-
- // 4、解析对象类型,取值顺序应和写入顺序一致
- ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());
- ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(bais));
-
- Object obj = ois.readObject();
- Person person = null;
- if (obj instanceof Person) {
- person = (Person) obj;
- }
-
- System.out.println("name----->" + person.getName());
- System.out.println("age----->" + person.getAge());
-
- // 5、释放资源
接收端控制台
文件在发送端首先使用FileInputStream读取,再写入ByteArrayOutputStrem并转为字节数组
发送端
- // 1、指定端口,创建发送端
-
- // 2、准备基本类型数据,转成字节数组
- File file = new File("src/test/1.png"); // 文件大小不超过接收端容器大小
- FileInputStream fis = new FileInputStream(file); // 也可直接传递文件地址
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- // flush代表每次读取和写入的大小,10K
- byte[] flush = new byte[1024*10];
- int len = -1;
- // 文件输入流读取最多flush.length字节的数据到字节数组,读取完毕返回-1
- while ((len = fis.read(flush)) != -1) {
- // 往字节输出流中写入读取出的数据
- baos.write(flush, 0, len);
- }
-
- byte[] datas = baos.toByteArray();
-
- // 3、将字节数组封装成包
- // 4、发送数据
- // 5、释放资源
接收端
- // 1、指定端口,创建接收端,此处的端口应对应发送端发送数据指定的端口
- // 2、准备容器,封装成DatagramPacket包
- // 3、阻塞式接收包
-
- // 4、解析基本类型,取值顺序应和写入顺序一致
- ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());
-
- File file = new File("src/test/copy.png"); // 需要写入的文件路径
- FileOutputStream fos = new FileOutputStream(file);
-
- byte[] flush = new byte[5];
- int len = -1;
- // 从数据包中的输入流里读取并写入文件输出流
- while ((len = bais.read(flush)) != -1) {
- fos.write(flush, 0, len);
- }
- fos.flush();
-
-
- // 5、释放资源
之前的例子都是单次的通信,多次通信只需要发送端循环接收控制台输入并发送,接收端循环接收数据包并解析即可
发送端
- // 1、指定端口,创建发送端
-
- // 2、准备数据,转成字节数组
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- while (true) {
- String str = br.readLine(); // 接收控制台输入
- byte[] datas = str.getBytes();
-
- // 3、将字节数组封装成包
- DatagramPacket packet = new DatagramPacket(datas, 0, datas.length,
- new InetSocketAddress("localhost", 9999));
-
- // 4、发送数据
- client.send(packet);
- if ("bye".equals(str)) {
- break;
- }
- }
-
- // 5、释放资源
接收端
- // 1、指定端口,创建接收端,此处的端口应对应发送端发送数据指定的端口
-
- // 2、准备容器,封装成DatagramPacket包
- while (true) {
- byte[] contanier = new byte[60*1024];
- DatagramPacket packet = new DatagramPacket(contanier, 0, contanier.length);
-
- // 3、阻塞式接收包
- server.receive(packet);
-
- // 4、解析包
- byte[] datas = packet.getData();
- int len = packet.getLength();
- String msg = new String(datas, 0, len);
- System.out.println(msg);
-
- if ("bye".equals(msg)) {
- break;
- }
- }
-
- // 5、释放资源
双向通信要求每一端,既能发送数据,也能接收数据。那就需要一个线程来执行发送端,一个线程执行接收端。也就需要我们把发送端和接受端封装成两个类并实现Runnable接口
发送端
- public class UdpSender implements Runnable{
- private DatagramSocket client;
- private BufferedReader br;
-
- private String toIP;
- private int toPort;
-
- private String sender;
-
- // 用构造方法来指定发送端端口,接收端ip+端口,和发送人
- UdpSender(int port, String toIP, int toPort, String sender) {
- this.toIP = toIP;
- this.toPort = toPort;
- this.sender = sender;
-
- try {
- client = new DatagramSocket(port);
- br = new BufferedReader(new InputStreamReader(System.in));
- } catch (SocketException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void run() {
- while (true) {
- String str = null;
- try {
- str = sender + ":" + br.readLine();
- byte[] datas = str.getBytes();
-
- // 3、将字节数组封装成包
- DatagramPacket packet = new DatagramPacket(datas, 0, datas.length,
- new InetSocketAddress(toIP, toPort));
-
- // 4、发送数据
- client.send(packet);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- // 5、释放资源
- client.close();
- }
- }
接收端
- public class UdpReceiver implements Runnable{
- private DatagramSocket server;
-
- // 指定接收端端口
- UdpReceiver(int port) {
- try {
- server = new DatagramSocket(port);
- } catch (SocketException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void run() {
- // 2、准备容器,封装成DatagramPacket包
- while (true) {
- byte[] contanier = new byte[60*1024];
- DatagramPacket packet = new DatagramPacket(contanier, 0, contanier.length);
-
- // 3、阻塞式接收包
- try {
- server.receive(packet);
- // 4、解析包
- byte[] datas = packet.getData();
- int len = packet.getLength();
- String msg = new String(datas, 0, len);
- System.out.println(msg);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- // 5、释放资源
- server.close();
- }
- }
创建一个学生类和教师类,分别启动发送和接收端口
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。