Java UDP通信 讲解与简单实现

UDP协议

UDP提供了一种无需建立连接就能发送数据的方式,即“喊话”,他不管接收者是否收到,只管发送,优点是占用资源少 不用像tcp那样建立可靠连接

DatagramSocket类

使用DatagramSocket类我们可以简单的封装一个socket,但是不同的是,这个socket不是像TCP的socket那样建立可靠连接,这个socket是一个抽象的“管道”,负责发送数据,而不维护流,也不维护连接状态

抽象的讲,创建DatagramSocket对象,相当于我们架起天线,准备接受,或者发送

接收端DatagramSocket的构造

在创建接收端的DatagramSocket对象时,需要指定两个参数,即侦听的端口和ip,默认是localhost

InetAddress addr = InetAddress.getByName("localhost");
int port = 54321;
DatagramSocket recv_socket = new DatagramSocket(port, addr);

发送端DatagramSocket的构造

在创建发送端的DatagramSocket对象时,我们不需要指定参数,因为目标主机的信息包含在数据里面,要在数据包里面指定,这个稍后会提到

DatagramSocket send_socket = new DatagramSocket();

DatagramPacket类

DatagramPacket类是抽象的数据包类,DatagramSocket正是用来发送或者接受DatagramPacket对象的管道。

如果把DatagramSocket比作天线,那么DatagramPacket就是发送的电磁波

和DatagramSocket类似,发送端和接收端的配置方式都不一样,接下来看一下如何构造DatagramPacket对象

接收端DatagramPacket对象的构造

因为接收端DatagramSocket已经指定了侦听的端口和ip,所以这个包只负责存数据,即我们只需要指定一个字节数组,并且传递给DatagramPacket,即可指定数据存放的DatagramPacket包

byte[] rbuf = new byte[1024];
DatagramPacket data = new DatagramPacket(rbuf, 1024);

发送端DatagramPacket对象的构造

发送端DatagramPacket就比较特殊,因为我们的发送socket只负责发送,不管发到哪里,而目标地址是写在UDP包里面的,所以我们不仅要指定数据所在的字节数组,还要传入目标主机的ip和端口

// 发送给服务端
String send_msg = "hello\r\n";
byte[] sbuf = send_msg.getBytes();
int send_port = 54321;
InetAddress addr = InetAddress.getByName(ip);
DatagramPacket resp = new DatagramPacket(sbuf, sbuf.length, addr, send_port);

例子:本地UDP通信

我们使用本机的54321端口作为服务端的接收端口,54322端口作为客户端的接收端口,避免自己发自己导致数据泛洪

在这里插入图片描述

服务端:UDPServer

import java.net.*;

public class UDPServer {
	
	int send_port = 54322;
	int recv_port = 54321;
	String ip = "localhost";
	
	public UDPServer() {
		
	}
	
	public UDPServer(String ip, int sport, int rport) {
		this.ip = ip;
		this.send_port = sport;
		this.recv_port = rport;
	}
	
	public void Lisent() throws Exception {
		
		// 创建发送和接收的UDPsocket
		DatagramSocket send_socket = new DatagramSocket();
		DatagramSocket recv_socket = new DatagramSocket(recv_port, InetAddress.getByName(ip));
		
		// 接收数据的DatagramPacket对象
		byte[] buf = new byte[1024];
		DatagramPacket data = new DatagramPacket(buf, 1024);
		while(true) {
			// 接受数据
			recv_socket.receive(data);	
			String msg = new String(buf);
			System.out.println("[服务端] 接受到客户端信息: " + msg);
			String rstr = "服务端收到消息" + msg;
			byte[] rbuf = rstr.getBytes();
			
			// 发送响应信息
			InetAddress caddr = data.getAddress();	// 客户端ip
			// 创建发送数据的DatagramPacket对象 需要指定目标ip和端口
			DatagramPacket resp = new DatagramPacket(rbuf, rbuf.length, caddr, send_port);
			send_socket.send(resp);
			
		}
	}
	
	public static void main(String[] args) throws Exception {
		UDPServer server = new UDPServer("127.0.0.1", 54322, 54321);
		server.Lisent();
	}
	
}

客户端:UDPClient

import java.net.*;
import java.util.*;

public class UDPClient {
	
	String ip = "localhost";
	int send_port = 54322;
	int recv_port = 54321;
	DatagramSocket send_socket = null;
	DatagramSocket recv_socket = null;

	UDPClient() {
		
	}
	
	UDPClient(String ip, int sport, int rport) throws Exception {
		this.ip = ip;
		this.send_port = sport;
		this.recv_port = rport;
		send_socket = new DatagramSocket();
		recv_socket = new DatagramSocket(recv_port, InetAddress.getByName(ip));
	}
	
	public void Send(String send_msg) throws Exception {
		
		// 发送给服务端
		byte[] sbuf = send_msg.getBytes();
		DatagramPacket resp = new DatagramPacket(sbuf, sbuf.length, InetAddress.getByName(ip), send_port);
		send_socket.send(resp);
		
		// 接受数据
		byte[] rbuf = new byte[1024];
		DatagramPacket data = new DatagramPacket(rbuf, 1024);
		recv_socket.receive(data);	
		String msg = new String(rbuf);
		System.out.println("[客户端] 接受到服务端信息: " + msg);
		
	}
	
	public static void main(String[] args) throws Exception {
		UDPClient client = new UDPClient("127.0.0.1", 54321, 54322);
		while(true) {
			client.Send(new Scanner(System.in).nextLine());
		}
	}
	
}

结果

客户端输入发送,服务端回显:
在这里插入图片描述

服务端显示:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章