Java网络编程-第三节:UDP数据报套接字(DatagramSocket)编程
Posted 快乐江湖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java网络编程-第三节:UDP数据报套接字(DatagramSocket)编程相关的知识,希望对你有一定的参考价值。
文章目录
一:Java数据报套接字通信模型
Java UDP通信模型:Java中使用UDP协议通信,主要依靠一下两个类
DatagramSocket
:创建UDP SocketDatagramPacket
:是UDP Socket发送和接受的数据报
一次发送和接收UDP数据报流程如下
多个请求流程如下
二:相关API详解
(1)DatagramSocket
DatagramSocket:用于构造UDP Socket,以发送和接收UDP数据报
构造方法如下
方法签名 | 方法说明 |
---|---|
DatagramSocket() | 创建一个UDP数据报 Socket,绑定到本机任意一个随机端口 ,一般用于客户端 |
DatagramSocket(int port) | 创建一个UDP数据报 Socket,绑定到本机任意指定端口 ,一般用于服务端 |
成员方法如下
方法签名 | 方法说明 |
---|---|
void receive(DatagramPacket p) | 从该Socket中接收数据报(如果未收到则会阻塞等待) |
void send(DatagramPacket p) | 由该Socket发送数据报(不会阻塞等待,直接发送) |
void close() | 关闭此Socket |
(2)DatagramPacket
DatagramPacket:是UDP Socket发送和接收的数据报
构造方法如下
方法签名 | 方法说明 |
---|---|
DatagramPacket(byet[] buf, int length) | 用于接收数据报,接收的数据保存在buf 数组中,length 指定接收长度 |
DatagramPacket(byet[] buf, int offset, int length, SocketAddress address) | 用于发送数据报,发送的数据为buf 数组,范围为从0到length ,address 是目的主机的IP和端口号 |
成员方法如下
方法签名 | 方法说明 |
---|---|
InetAddress getAddress() | 从接收的数据报中获取发送端主机IP地址;或从发送的数据报中获取接收端主机IP地址 |
int getPort() | 从接收的数据报中获取发送端主机端口号;或从发送的数据报中获取接收端主机端口号 |
bye[] getData() | 获取数据报中的数据 |
三:UDP通信示例一:客户端发送什么服务端就返回什么
- 注意:这个功能比较简单,但主要目的是为了演示上面所讲API的用法
(1)代码
服务端IP
地址设置为127.0.0.1
,也即本地环回,也即自己发自己收,数据会完整走一遍协议
服务端:UDPServer
:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPServer
// 构造DatagramSocket
private DatagramSocket socket = null;
public UDPServer(int port) throws SocketException
// 服务端需要绑定一个端口号
socket = new DatagramSocket(port);
// 服务端启动
public void start() throws IOException
System.out.println("服务器启动!");
// 服务端随时等待接收客户端请求
while (true)
/*
1. 接受请求并解析
构造一个DatagramPacket对象requestPacket用于接受客户端发来的数据报,保存在byte[]
为了方便查看信息,需要使用 requestPacket的getData()方法将其转换为String
*/
DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
socket.receive(requestPacket);
String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
/*
2. 拿到客户端的请求request后,将其交给一个方法process进行处理,process方法会返回响应response
*/
String response = process(request);
/*
3. 将响应回复给客户端
构造一个DatagramPacket对象responsePacket用于给客户端回复响应response ,response是String
所以需要使用用getBytes()方法将其转化为byte[]
客户端发来的requestPacket数据报中携带有客户端的Ip地址和端口号,使用getSocketAddress()获得
*/
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
requestPacket.getSocketAddress());
socket.send(responsePacket);
// 打印信息
System.out.println("【客户端IP: " + requestPacket.getAddress().toString()
+ "客户端口号:" + requestPacket.getPort() + "】"
+ ":\\"" + request + "\\"" + ", 服务端回复: " + "\\"" + response + "\\"");
// 回显服务器,客户端发什么服务端就回复什么
public String process(String request)
return request;
public static void main(String[] args) throws IOException
// 服务端监听9090端口
UDPServer server = new UDPServer(9090);
server.start();
客户端:UDPClient
:
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UDPClient
DatagramSocket socket = null;
// 客户端需要指定好服务端的IP和端口号,然后构建一个Socket地址
private SocketAddress ADDRESS = null;
public UDPClient(String serverIP, int serverPort) throws SocketException
ADDRESS = new InetSocketAddress(serverIP, serverPort);
socket = new DatagramSocket();
// 客户端启动
public void start() throws IOException
Scanner scanner = new Scanner(System.in);
while (true)
// 1. 读取客户端用户输入
System.out.print("input: ");
String request = scanner.next();
/*
2. 发送请求给服务端
构造一个DatagramPacket对象requestPacket用于给服务端发送数据报,注意需要将String转换为byte[]
同时传入服务端的ADDRESS(ip地址和port)
*/
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
ADDRESS);
socket.send(requestPacket);
// 3. 从服务端获取响应
DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
// 打印信息
System.out.println("服务端回复:" + response);
public static void main(String[] args) throws IOException
UDPClient client = new UDPClient("127.0.0.1", 9090);
client.start();
(2)效果展示
一个服务端一个客户端
一个服务端多个客户端
注意如果需要运行多个UDPClient
实例,需要在Run/Debug Configurations
中选中Allow multiple instances
这里启动三个客户端
(3)分析
对于服务端(UDPServer
类):
-
构造方法(
public UDPServer(int port)
)- 需要建立一个
DatagramSocket
并绑定一个指定的端口号port
,也即DatagramSocket socket =new DatagramSocket(port)
。服务端绑定端口号的原因是因为程序运行在服务器上是确定的、可控的
- 需要建立一个
-
服务端处理逻辑(
public void start()
)-
①:接受请求并解析
- 需要构造一个
DatagramPacket
用于接受客户端发来的数据报,会保存在byte[]
中,也即DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096)
- 接受行为由
socket
完成,也即socket.receive(requestPacket)
- 接受到的
requestPacket
其类型为byte[]
,所以需要把它转为String
以便于查看,也即String request = new String(requestPacket.getData(), 0, requestPacket.getLength())
- 需要构造一个
-
②:处理请求
- 拿到解析后的
request
后,需要对该request
进行处理(交给方法process
),不同的业务逻辑会有不同的处理方法。这里我们只是简单的“回显”一下即可,也即客户端发什么服务端就回复什么
- 拿到解析后的
-
③:将处理结果(响应)回复给客户端
- 需要构造一个
DatagramPacket
用于给客户端回复响应response
,在构造时要将类型为String
的respnse
转化为byte[]
,同时使用requestPacket.getSocketAddress()
获取到客户端的IP
和port
(因为服务端总要知道客户端的具体地址才能发送),也即DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress())
- 发送行为由
socket
完成,也即socket.send(responsePacket);
- 需要构造一个
-
④:打印相关信息
-
-
main
方法- 构造
UDPServer
对象,并绑定指定端口号,如9090
,也即UDPServer server = new UDPServer(9090)
- 启动服务端,也即
server.start()
- 构造
对于客户端(UDPClient
类):
-
构造方法(
public UDPClient(String serverIP, int serverPort)
)-
需要建立一个
DatagramSocket
,但不指定端口号,也即DatagramSocket socket =new DatagramSocket()
。客户端无需绑定端口号是因为客户端上运行状况复杂,端口号占用情况各不相同,无法保证所指定的端口号在数据报来临时一定是空闲的,所以这里让系统自动指定空闲端口号即可 -
需要建立一个
InetSocketAddress
,传入服务端serverIP
和serverPort
,也即SocketAddress ADDRESS = new InetSocketAddress(serverIP, serverPort)
,这里的serverPort
就是服务端中所指定的那个port
。之所以这样做是因为客户端发送时必须要知道服务端的IP
地址和port
InetSocketAddress
是SocketAddress
的子类
-
-
客户端处理逻辑(
public void start()
)-
①:读取客户端中用户的输入
- 使用
Scanner
接受即可,也即String request = scanner.next()
- 使用
-
②:发送请求给服务端
- 需要构造一个
DatagramPacket
给服务端发送数据报,注意需要将类型String
的request
转化为byte[]
,同时传入服务端的ADDRESS
。也即DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length, ADDRESS);
- 发送行为由
socket
完成,也即socket.send(requestPacket)
- 需要构造一个
-
③:从服务端获取响应
- 需要构造一个
DatagramPacket
用于接受服务端端发来的数据报,会保存在byte[]
中,也即DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096)
- 接受行为由
socket
完成,也即socket.receive(responsePacket)
- 接受到的
responsePacket
其类型为byte[]
,所以需要把它转为String
以便于查看,也即String response = new String(responsePacket.getData(), 0, resoibsePacket.getLength())
- 需要构造一个
-
④:打印相关信息
-
-
main
方法- 构造
UDPClient
对象,并给定服务端IP
和port
,也即UDPClient client = new UDPClient("127.0.0.1", 9090)
- 启动客户端,也即
client.start()
- 构造
四:UDP通信示例二:实现简单的翻译功能
一个服务器通信的基本流程就是上面所展示的那样,最核心的区别在于“业务处理逻辑”不同,这里我们对客户端进行改造,让其实现一个简单的“英翻汉”功能
- 词典词汇量虽然屈指可数,但整体逻辑就像下面演示的那样,当然你也可以调用一些翻译API接口(例如百度)
(1)代码
客户端:UDPTranslateClient
: 让此类继承上面的UDPClient
然后重写 process
方法即可
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
public class UDPTranslateServer extends UDPServer
// 查询字典
private Map<String, String> dict = new HashMap<>();
public UDPTranslateServer(int port) throws SocketException
super(port);
dict.put("cat", "猫");
dict.put("dog", "狗");
dict.put("pig", "猪");
dict.put("wolf", "狼");
// 重写process方法实现查询词典功能
@Override
public String process(String request)
return dict.getOrDefault(request, "没有这个词");
public static void main(String[] args) throws IOException
UDPTranslateServer udpTranslateServer = new UDPTranslateServer(9090);
udpTranslateServer.start();
(2)效果展示
以上是关于Java网络编程-第三节:UDP数据报套接字(DatagramSocket)编程的主要内容,如果未能解决你的问题,请参考以下文章