目录
一、DatagramSocket API
DatagramSocket是UDP Socket,用于发送和接收UDP数据报,针对服务器上启动的网络服务,对应到服务器上用来接收用户请求的进程。
1.1、DatagramSocket构造方法
方法签名 | 方法说明 |
DatagramSocket() | 创建一个UDP数据报套接字的Socket,绑定到本机任意一个端口(一般用于客户端) |
DatagramSocket(int pot) | 创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端) |
1.2、DatagramSocket方法
方法签名 | 方法说明 |
void receive(DatagramPacket p) | 从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待) |
void send(DatagramPacket p) | 从此套接字发送数据包(不会阻塞等待,直接发送) |
void close() | 关闭此数据报套接字 |
网络编程在收发数据的过程中主要是对网卡进行操作。
- 接收数据,也就是对网卡进行读取。
- 发送数据,也就是对网卡进行写入。
计算机中所有设备都是文件,那么网卡也被当作一个文件管理系统管理起来了,那么对网卡的写入和读取其实就是简单的对文件进行读取和写入的封装。
DatagramSocket其中部分功能就是对读取和写入的封装。对应的就是receive()和send()方法。
二、DatagramPacket API
DatagramPacket是UDP Socket,用于发送和接收的数据报,针对通信的报文。
2.1、DatagramPacket构造方法
方法签名 | 方法说明 |
DatagramPacket(byte[] buf,int length) | 构造一个DatagramPacket以用来接收数据报,接受的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length) |
DatagramPacket(byte[] buf,int offset,int length,SocketAddress address) | 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二和第三个参数offset,length)。address指定目的主机的Ip和端口号 |
2.2、DatagramPacket方法
方法签名 | 方法说明 |
InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址 |
int getPort() | 从接受的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端的端口号 |
byte[] getData() | 获取数据报中的数据 |
三、示例
实现字典查询器
- 客户端先接收键盘输入,表示要查找的字符。
- 发送请求:用户输入的数据打包成DatagramPacket,作为数据报发送到服务端 。
- 服务端接收并处理请求:接收请求数据,根据该请求数据来计算响应。
- 服务端返回响应:使用DatagramPacket来封装相应数据,作为响应的数据报,返回给客户端。
- 客户端接收响应:简单的打印输出所有的响应内容。
1、定义字典类,将我们要查找的词导入到字典类中
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
/**
* 基于UDP的字典查询器
*/
public class UDPDictServer extends UDPEchoServer {
Map<String,String> map;
public UDPDictServer(int port) throws SocketException {
super(port);
map=new HashMap<>();
map.put("狗","dog");
map.put("猫","cat");
map.put("老鼠","mouse");
map.put("蛇","snake");
map.put("鸡","蔡徐坤");
map.put("鸭子","duck");
map.put("三万", "土鸡");
map.put("小寄","dog");
}
@Override
protected String process(String request) {
return map.getOrDefault(request, "查无此词");
}
public static void main(String[] args) throws IOException {
//初始化字典服务器
UDPDictServer server=new UDPDictServer(11111);
server.start();
}
}
2、实现UDP服务端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
/**
* 基于UDP的服务端
*/
public class UDPEchoServer {
//声明一个可以提供UDP协议的对象
private DatagramSocket socket;
//通过构造方法来指定服务的端口号
public UDPEchoServer(int port) throws SocketException {
//校验端口号
if(port<1||port>65535){
throw new RuntimeException("端口号应在1025~65535之间");
}
//实现UDP服务
this.socket=new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动...");
//循环处理请求
while(true){
//1、使用DatagramPacket接收用户的请求
DatagramPacket requestPacket=new DatagramPacket(new byte[1024],1024);
//2、接收数据
socket.receive(requestPacket);
//3、解析接收的数据
String request=new String(requestPacket.getData(),0,requestPacket.getLength());
//4、根据请求来计算响应
String response=process(request);
//5、使用DatagramPacket来封装相应数据
DatagramPacket responsePacket=new DatagramPacket(response.getBytes(StandardCharsets.UTF_8),
response.getBytes().length,requestPacket.getSocketAddress());
//6、发送响应
socket.send(responsePacket);
//7、打印日志
System.out.printf("[%s :%d] request=%s,response=%s\n", requestPacket.getAddress().toString()
,requestPacket.getPort(),request,response);
}
}
protected String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UDPEchoServer server=new UDPDictServer(11111);
server.start();
}
}
3、实现UDP客户端
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/**
* 基于UDP的客户端
*/
public class UDPEchoClient {
//声明一个Socket对象
private DatagramSocket socket;
private String serverIp;
private int serverPort;
//通过构造方法初始化socket,指定端口地址,ip
public UDPEchoClient(String serverIp, int serverPort) throws SocketException {
this.socket=new DatagramSocket();
this.serverIp = serverIp;
this.serverPort = serverPort;
}
//启动客户端服务
public void start() throws IOException {
System.out.println("客户端已启动...");
//循环处理客户端输入
while(true){
System.out.println("->");
//定义Scanner
Scanner sc=new Scanner(System.in);
//1、获取用户的输入
String request=sc.nextLine();
if(request==null||request.equals("")){
System.out.println("您输入了一个空数据!!!");
continue;
}
//2、用户输入的数据打包成DatagramPacket
//3、创建SocketAddress对象,表示服务器的IP和端口号
SocketAddress address=new InetSocketAddress(serverIp, serverPort);
DatagramPacket requestPacket=new DatagramPacket(request.getBytes(StandardCharsets.UTF_8),
request.getBytes().length,address);
//4、发送数据到服务器
socket.send(requestPacket);
//5、接收服务器的响应
DatagramPacket responsePacket=new DatagramPacket(new byte[1024],1024);
socket.receive(responsePacket);
//6、解析得到的响应数据
String response=new String(responsePacket.getData(),0,responsePacket.getLength(),"UTF-8");
//7、打印响应日子
System.out.printf("request=%s,response=%s.\n",request,response);
}
}
public static void main(String[] args) throws IOException {
//初始化客户端服务,客户端口号和服务端口号要保持一致,不然就会访问不到
UDPEchoClient client=new UDPEchoClient("127.0.0.1", 11111);
client.start();
}
}
运行结果: