Java网络编程—UDP

传输层协议:TCP/UDP
  TCP:安全的,面向连接的
  UPD:不安全的,非面向连接的(比较高效)
 
UDP传输协议:一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务
 
特点:
  非面向连接,传输不可靠,可能丢失
  发送不管对方是否准备好,接收方收到也不确认
  可以广播发送
  非常简单的协议,开销小
 

UDP操作字节数组(字节数组与包裹打交道)
  通过封装成包—>拆包—>封包—>拆包
 
DatagramSocket:用于发送或接收数据报到套接字
DatagramPacket:数据包
 
在应用层通过Socket 使用传输层(TCP/UDP)的服务
在这里插入图片描述

UDP 基本流程 代码示例

代码示例:

/*
 * 基本流程:发送端
 * 1、使用DatagramSocket 指定端口 创建发送端
 * 2、准备数据一定转成字节数组 
 * 3、封装成DatagramPacket 包裹,需要指定目的地(IP和端口)
 * 4、发送包裹send(DatagramPacket p)
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpClient {
 
	public static void main(String[] args) throws Exception {
		System.out.println("发送方启动中...");
		// 1、使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		// 2、准备数据一定转成字节数组 
		String data = "Java网络编程";
		byte[] datas = data.getBytes();
		// 3、封装成DatagramPacket 包裹,需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost", 9999));
		// 4、发送包裹send(DatagramPacket p)
		client.send(packet);
		// 5、释放资源
		client.close();
	}
}
/*
 * 基本流程:接收端
 * Address already in use: Cannot bind 同一个协议下端口不允许冲突
 * 1、使用DatagramSocket 指定端口 创建接收端
 * 2、准备容器 封装成DatagramPacket 包裹
 * 3、阻塞式接收包裹receive(DatagramPacket p)
 * 4、分析数据
 * 	  byte[]  getData()
 *    	   	  getLength()
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpServer {

	public static void main(String[] args) throws Exception {
		System.out.println("接收方启动中...");
		// 1、使用DatagramSocket 指定端口 创建接收端
		DatagramSocket server = new DatagramSocket(9999);
		// 2、准备容器 封装成DatagramPacket 包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		// 3、阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);//阻塞式
		// 4、分析数据
		// 	  byte[]  getData()
		//    	   	  getLength()
		byte[] datas = packet.getData();
		int len = packet.getLength();
		System.out.println(new String(datas,0,len));
		// 5、释放资源
		server.close();
	}
}

UDP 基本类型 代码示例

代码示例:

/*
 * 基本类型:发送端
 * 1、使用DatagramSocket 指定端口 创建发送端
 * 2、将基本类型 转成字节数组 
 * 3、封装成DatagramPacket 包裹,需要指定目的地
 * 4、发送包裹send(DatagramPacket p)
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */ 
public class UdpTypeClient {

	public static void main(String[] args) throws Exception {
		System.out.println("发送方启动中...");
		// 1、使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		// 2、将基本类型 转成字节数组 
		// 写出
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
		// 操作数据类型 + 数据
		dos.writeUTF("编码辛酸泪");
		dos.writeInt(18);
		dos.writeBoolean(false);
		dos.writeChar('a');
		dos.flush();
		byte[] datas = baos.toByteArray();
		// 3、封装成DatagramPacket 包裹,需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost", 9999));
		// 4、发送包裹send(DatagramPacket p)
		client.send(packet);
		// 5、释放资源
		client.close();
	}
}
/*
 * 基本类型:接收端
 * Address already in use: Cannot bind 同一个协议下端口不允许冲突
 * 1、使用DatagramSocket 指定端口 创建接收端
 * 2、准备容器 封装成DatagramPacket 包裹
 * 3、阻塞式接收包裹receive(DatagramPacket p)
 * 4、分析数据   将字节数组还原为对应的类型
 * 	  byte[]  getData()
 *    	   	  getLength()
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpTypeServer {

	public static void main(String[] args) throws Exception {
		System.out.println("接收方启动中...");
		// 1、使用DatagramSocket 指定端口 创建接收端
		DatagramSocket server = new DatagramSocket(9999);
		// 2、准备容器 封装成DatagramPacket 包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		// 3、阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);//阻塞式
		// 4、分析数据  将字节数组还原为对应的类型
		// 	  byte[]  getData()
		//    	   	  getLength()
		byte[] datas = packet.getData();
		int len = packet.getLength();
		// 读取
		DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));
		// 顺序与写出一致
		String msg = dis.readUTF();
		int age = dis.readInt();
		boolean flag = dis.readBoolean();
		char ch = dis.readChar();
		System.out.println(msg+"-->"+flag);
		// 5、释放资源
		server.close();
	}
}

UDP 引用类型 代码示例

代码示例:

/*
 * 引用类型:发送端
 * 1、使用DatagramSocket 指定端口 创建发送端
 * 2、将基本类型 转成字节数组 
 * 3、封装成DatagramPacket 包裹,需要指定目的地
 * 4、发送包裹send(DatagramPacket p)
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpObjClient {

	public static void main(String[] args) throws Exception {
		System.out.println("发送方启动中...");
		// 1、使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		// 2、将基本类型 转成字节数组 
		// 写出
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(baos));
		//操作数据类型 + 数据
		oos.writeUTF("编码辛酸泪");
		oos.writeInt(18);
		oos.writeBoolean(false);
		oos.writeChar('a');
		// 对象
		oos.writeObject("谁解其中味");
		oos.writeObject(new Date());
		Employee emp = new Employee("马云",400);
		oos.writeObject(emp);
		oos.flush();
		byte[] datas = baos.toByteArray();
		// 3、封装成DatagramPacket 包裹,需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost", 9999));
		// 4、发送包裹send(DatagramPacket p)
		client.send(packet);
		// 5、释放资源
		client.close();
	}
}
/*
 * 引用类型:接收端
 * Address already in use: Cannot bind 同一个协议下端口不允许冲突
 * 1、使用DatagramSocket 指定端口 创建接收端
 * 2、准备容器 封装成DatagramPacket 包裹
 * 3、阻塞式接收包裹receive(DatagramPacket p)
 * 4、分析数据   将字节数组还原为对应的类型
 * 	  byte[]  getData()
 *    	   	  getLength()
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpObjServer {

	public static void main(String[] args) throws Exception {
		System.out.println("接收方启动中...");
		// 1、使用DatagramSocket 指定端口 创建接收端
		DatagramSocket server = new DatagramSocket(9999);
		// 2、准备容器 封装成DatagramPacket 包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		// 3、阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);//阻塞式
		// 4、分析数据  将字节数组还原为对应的类型
		// 	  byte[]  getData()
		//    	   	  getLength()
		byte[] datas = packet.getData();
		int len = packet.getLength();
		// 读取 -->反序列化
		ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));
		//顺序与写出一致
		String msg = ois.readUTF();
		int age = ois.readInt();
		boolean flag = ois.readBoolean();
		char ch = ois.readChar();
		System.out.println(flag);
		//对象的数据还原
		Object str = ois.readObject();
		Object data = ois.readObject();
		Object employee = ois.readObject();
		
		if (str instanceof String) {
			String strObj = (String) str;
			System.out.println(strObj);
		}
		if (data instanceof Data) {
			Data dateObj = (Data) data;
			System.out.println(dateObj);
		}
		if (employee instanceof Employee) {
			Employee empObj = (Employee) employee;
			System.out.println(empObj.getName()+"-->");
		}
		// 5、释放资源
		server.close();
	}
}
//Javabean 封装数据
public class Employee implements Serializable{
	private transient String name; // 该数据不需要序列化
	private double salary;
	public Employee() {
		
	}
	public Employee(String name,double salary) {
		this.name = name;
		this.salary = salary;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		
	}
}

UDP 文件上传 代码示例

代码示例:

/*
 * 文件上传:发送端
 * 1、使用DatagramSocket 指定端口 创建发送端
 * 2、将文件 转成字节数组 
 * 3、封装成DatagramPacket 包裹,需要指定目的地
 * 4、发送包裹send(DatagramPacket p)
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpFileClient {

	public static void main(String[] args) throws Exception {
		System.out.println("发送方启动中...");
		// 1、使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		// 2、将文件 转成字节数组 
		// 写出
		byte[] datas = IOUtils.fileToByteArray("p.png");
		
		// 3、封装成DatagramPacket 包裹,需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost", 9999));
		// 4、发送包裹send(DatagramPacket p)
		client.send(packet);
		// 5、释放资源
		client.close();
	}
}
/*
 * 文件存储:接收端
 * Address already in use: Cannot bind 同一个协议下端口不允许冲突
 * 1、使用DatagramSocket 指定端口 创建接收端
 * 2、准备容器 封装成DatagramPacket 包裹
 * 3、阻塞式接收包裹receive(DatagramPacket p)
 * 4、分析数据   将字节数组还原为对应的类型
 * 	  byte[]  getData()
 *    	   	  getLength()
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpFileServer {

	public static void main(String[] args) throws Exception {
		System.out.println("接收方启动中...");
		// 1、使用DatagramSocket 指定端口 创建接收端
		DatagramSocket server = new DatagramSocket(9999);
		// 2、准备容器 封装成DatagramPacket 包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		// 3、阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);//阻塞式
		// 4、分析数据  将字节数组还原为文件
		// 	  byte[]  getData()
		//    	   	  getLength()
		byte[] datas = packet.getData();
		int len = packet.getLength();
		// 读取
		// datas为数据
		IOUtils.byteArrayToFile(datas, "src/copy.png");
		// 5、释放资源
		server.close();
	}
}
/*
 * 1、图片读取到字节数组中
 * 2、字节数组写出到文件(图片)
 */
public class IOUtils {
	
	public static void main(String[] args) {
		// 图片转成字节数组
		byte[] datas = fileToByteArray("E:/gongfang/JavaDemo/linweimao/javaWork/Demo/IO_study02/src/com/lwm/io/p.png");
		System.out.println(datas.length);
		byteArrayToFile(datas, "p-byte.png");
	}
	/*
	 * 1、图片读取到字节数组中
	 * 	  1)、图片到程序		FileInputStream
	 *    2)、程序到字节数组   ByteArrayOutputStream
	 */
	public static byte[] fileToByteArray(String filePath) {
		// 1、创建源与目的地
		File src = new File(filePath);
		byte[] dest = null;
		// 2、选择流
		InputStream is = null;
		ByteArrayOutputStream baos = null;
		try {
			is = new FileInputStream(src);
			baos = new ByteArrayOutputStream();
			// 3、操作(分段读取)
			byte[] flush = new byte[1024 * 10];// 缓冲容器
			int len = -1;// 接收长度
			try {
				while ((len = is.read(flush)) != -1) {
					// 写出到字节数组中
					baos.write(flush,0,len);
					
				}
				baos.flush();
				return baos.toByteArray();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			// 4、释放资源
			try {
				if (null != is) {
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();

			}
		}
		return null;
	}
	
	/*
	 * 2、字节数组写出到文件(图片)
	 * 	  1)、字节数组读取到程序  ByteArrayInputStream
	 *    2)、程序到文件  FileOutputStream
	 */
	public static void byteArrayToFile(byte[] src,String filePath) {
		// 1、创建源
		File dest = new File(filePath);
		// 2、选择流
		InputStream is = null;
		OutputStream os = null;
		try {
			is = new ByteArrayInputStream(src);
			os = new FileOutputStream(dest);
			// 3、操作(分段读取)
			byte[] flush = new byte[5];// 缓冲容器
			int len = -1;// 接收长度
			while ((len = is.read(flush)) != -1) {
				os.write(flush,0,len);
			}
			os.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 释放资源
			try {
				if (null != os) {
					os.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}
}

UDP 多次交流 代码示例

// 能够发送多次
// 只能发送端说话,接收端接收(接收端说不了话)

代码示例:

// 能够发送多次
// 只能发送端说话,接收端接收(接收端说不了话)
/*
 * 多次交流:发送端
 * 1、使用DatagramSocket 指定端口 创建发送端
 * 2、准备数据一定转成字节数组 
 * 3、封装成DatagramPacket 包裹,需要指定目的地
 * 4、发送包裹send(DatagramPacket p)
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpTalkClient {

	public static void main(String[] args) throws Exception {
		System.out.println("发送方启动中...");
		// 1、使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		// 2、准备数据一定转成字节数组 
		// 用控制台进行交流
		// BufferedReader为字符流   System.in 为字节流 所以要转换(使用 InputStreamReader)
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		while (true) {
			String data = reader.readLine();
			byte[] datas = data.getBytes();
			// 3、封装成DatagramPacket 包裹,需要指定目的地
			DatagramPacket packet = new DatagramPacket(datas, 0, datas.length,
					new InetSocketAddress("localhost", 9999));
			// 4、发送包裹send(DatagramPacket p)
			client.send(packet);
			if (data.equals("bye")) {
				break;
			}
		}
		// 5、释放资源
		client.close();
	}
}
//能够接收多次

//只能发送端说话,接收端接收(接收端说不了话)
/*
 * 多次交流:接收端
 * Address already in use: Cannot bind 同一个协议下端口不允许冲突
 * 1、使用DatagramSocket 指定端口 创建接收端
 * 2、准备容器 封装成DatagramPacket 包裹
 * 3、阻塞式接收包裹receive(DatagramPacket p)
 * 4、分析数据
 * 	  byte[]  getData()
 *    	   	  getLength()
 * 5、释放资源
 * 
 * DatagramSocket:用于发送或接收数据报到套接字
 * DatagramPacket:数据包
 */
public class UdpTalkServer {

	public static void main(String[] args) throws Exception {
		System.out.println("接收方启动中...");
		// 1、使用DatagramSocket 指定端口 创建接收端
		DatagramSocket server = new DatagramSocket(9999);
		while (true) {
			// 准备不同的容器进行接收控制台的输入
			// 2、准备容器 封装成DatagramPacket 包裹
			byte[] container = new byte[1024*60];
			DatagramPacket packet = new DatagramPacket(container,0,container.length);
			// 3、阻塞式接收包裹receive(DatagramPacket p)
			server.receive(packet);//阻塞式
			// 4、分析数据
			// 	  byte[]  getData()
			//    	   	  getLength()
			byte[] datas = packet.getData();
			int len = packet.getLength();
			String data = new String(datas,0,len);
			System.out.println(data);
			if (data.equals("bye")) {
				break;
			}
		}
		// 5、释放资源
		server.close();
	}
}

UDP 多次交流,加入多线程,实现双向交流 模拟在线咨询

代码示例:

/*
 * 接收端:使用面向对象封装
 * 使用面向对象封装:加入属性、加入方法、加入构造器,然后在玩类和类的关系(接口、继承)
 */
public class TalkReceive implements Runnable{
	private DatagramSocket server;
	private String from;

	public TalkReceive(int port,String from) {
		this.from = from;
		try {
			server = new DatagramSocket(port);
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		while (true) {
			// 准备不同的容器进行接收控制台的输入
			// 2、准备容器 封装成DatagramPacket 包裹
			byte[] container = new byte[1024*60];
			DatagramPacket packet = new DatagramPacket(container,0,container.length);
			// 3、阻塞式接收包裹receive(DatagramPacket p)
			try {
				server.receive(packet); //阻塞式
				// 4、分析数据
				byte[] datas = packet.getData();
				int len = packet.getLength();
				String data = new String(datas,0,len);
				System.out.println(from+":"+data);
				if (data.equals("bye")) {
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}	
		}
		// 5、释放资源
		server.close();
	}
}
/*
 * 发送端:使用面向对象封装
 * 使用面向对象封装:加入属性、加入方法、加入构造器,然后在玩类和类的关系(接口、继承)
 */
public class TalkSend implements Runnable{

	private DatagramSocket client;
	private BufferedReader reader;
	private String toIP;
	private int toPort;
	public TalkSend(int port,String toIP,int toPort) {
		this.toIP = toIP;
		this.toPort = toPort;
		try {
			client = new DatagramSocket(port);
			reader = new BufferedReader(new InputStreamReader(System.in));
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void run() {
		while (true) {
			String data;
			try {
				data = reader.readLine();
				byte[] datas = data.getBytes();
				// 3、封装成DatagramPacket 包裹,需要指定目的地
				DatagramPacket packet = new DatagramPacket(datas, 0, datas.length,
						new InetSocketAddress(this.toIP, this.toPort));
				// 4、发送包裹send(DatagramPacket p)
				client.send(packet);
				if (data.equals("bye")) {
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 5、释放资源
					client.close();
	}
}
/* 
 * 加入多线程,实现双向交流  模拟在线咨询
 */
public class TalkTeacher {

	public static void main(String[] args) {
		new Thread(new TalkReceive(9999,"学生")).start();// 接收
		new Thread(new TalkSend(5555,"localhost",8888)).start();// 发送
	}
}
/*
 * 加入多线程,实现双向交流  模拟在线咨询
 */ 
public class TalkStudent {

	public static void main(String[] args) {
		new Thread(new TalkSend(7777,"localhost",9999)).start();// 发送
		new Thread(new TalkReceive(8888,"老师")).start();// 接收
	}
}
发布了45 篇原创文章 · 获赞 1 · 访问量 5225

猜你喜欢

转载自blog.csdn.net/weixin_42814000/article/details/104394031
今日推荐