目录
两个核心类:DatagramSocket API和DatagramPacket API
1.DatagramSocket API
DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。
1.1DatagramSocket 构造方法:
方法签名 | 方法说明 |
DatagramSocket() | 创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口 (一般用于客户端) |
DatagramSocket(intport) | 创建一个UDP数据报套接字的Socket,绑定到本机指定的端口 (一般用于服务端) |
socket对象,代表操作系统中的一个socket文件,代表网卡硬件设备抽象表现
1.2DatagramSocket 方法:
方法签名 | 方法说明 |
void receive(DatagramPacket p) | 从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待) |
void send(DatagramPacketp) | 从此套接字发送数据报包(不会阻塞等待,直接发送) |
void close() | 关闭此数据报套接字 |
2.DatagramPacket API
表示了一个UDP数据报,每次发送/接收数据,都是在传输一个DatagramPacket对象
2.1DatagramPacket 构造方法:
方法签名 | 方法说明 |
DatagramPacket(byte[]buf, int length) | 构造一个DatagramPacket以用来接收数据报,接收的数据,(字节数组,长度) |
DatagramPacket(byte[]buf, int offset, int length,SocketAddress address) | 构造一个DatagramPacket以用来发送数据报,发送的数据为(字节数组,长度,目的主机和端口号) |
2.2DatagramPacket 方法:
方法签名 | 方法说明 |
InetAddressgetAddress() | 从接收的数据报中,获取发送端主机IP地址; 或从发送的数据报中,获取接收端主机IP地址 |
int getPort() | 从接收的数据报中,获取发送端主机的端口号; 或从发送的数据报中,获取接收端主机端口号 |
byte[] getData() | 获取数据报中的数据 |
3.示例1:回显服务
请求内容是什么,得到响应就是什么
3.1服务器
3.1.1步骤
- 进行网络编程,第一步要准备好socket实例
- 然后构造服务器对象,要显示绑订端口号,端口号用来区分一个应用程序
- 启动服务器-UDP不需要建立连接,直接接收从客户端来的数据即可
- 读取客户端请求--把字节数组包装
- 为了接受数据,要先准备一个空的DatagramPacket对象,由receive来进行填充资源
- requestPacket一个空字节数组,socket.receive装信息的字节数组
- 把DatagramPacket解析成一个String
- 根据请求计算响应(因为是回显服务,2省略)
- 由于是回显服务,响应和请求一样,对于一个真实的服务器,过程是最复杂的
- 把响应写回到客户端
- response.getBytes()这个参数不是一个空的字节数组,response是刚才根据请求计算得到响应,非空的
- DatagramPacket中的数据就是String response的数据
- response.getBytes().length是字节的个数,response.length是字符的个数,这里传入的是字节类型
- new DatagramPacket发送数据要指定地址和端口,谁发的返回给谁, requestPacket.getSocketAddress()相当于一个类,包含了IP和端口
- 读取客户端请求--把字节数组包装
3.1.2代码
public class UdpEchoServer {
private DatagramSocket socket=null;
public UdpEchoServer(int port) throws SocketException {
socket=new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("启动服务器");
while(true){
DatagramPacket requestPacket=new DatagramPacket(new byte[1024],1024);
socket.receive(requestPacket);
String request=new String(requestPacket.getData(),0, requestPacket.getLength());
String response=process(request);
DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
System.out.printf("[%s:%d] req:%s,resp:%s\n", requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);
socket.send(responsePacket);
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer server=new UdpEchoServer(9090);
server.start();
}
}
3.2客户端
3.2.1步骤
- 客户端构造socket对象不在手动指定端口号
- 启动客户端
- 从控制台读取用户输入的字符串
- 把用户输入的内容,构造成UDP请求,并发送
- 请求包含两部分信息:
- 数据的内容:request字符串
- 数据发给谁:服务器的IP+端口
- 请求包含两部分信息:
- 从服务器读取响应数据,并解析
- 把响应结果显示到控制台
3.2.2代码
public class UdpEchoClient {
private DatagramSocket socket=null;
private String serverIP;
private int serverPort;
public UdpEchoClient(String ip,int port) throws SocketException {
socket=new DatagramSocket();
serverIP=ip;
serverPort=port;
}
public void start() throws IOException {
Scanner scanner=new Scanner(System.in);
while(true){
//1.从控制台读取用户输入的字符串
System.out.println("=>");
String request=scanner.next();
//2.把用户输入的内容,构造成UDP请求,并发送
DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),
request.getBytes().length, InetAddress.getByName("127.0.0.1"),9090);
socket.send(requestPacket);
//3.从服务器读取响应数据,并解析
DatagramPacket responsePacket=new DatagramPacket(new byte[1024],1024);
socket.receive(responsePacket);
String response=new String(responsePacket.getData(),0,
responsePacket.getLength(),"UTF-8");
//4.把响应结果显示到控制台
System.out.println("req:"+request+", res: "+response);
}
}
public static void main(String[] args) throws IOException {
UdpEchoClient client=new UdpEchoClient("127.0.0.1",9090);
client.start();
}
}
4实例2:翻译程序
请求是简单的英文单词,响应是英文单词的翻译
客户端不换,服务器进行调整,主要调整process方法
新建UdpDicServer类继承UdpEchoServer,重写process方法
public class UdpDicServer extends UdpEchoServer{
private HashMap<String,String> dict=new HashMap<>();
public UdpDicServer(int port) throws SocketException {
super(port);
dict.put("cat","小猫");
dict.put("dog","小狗");
dict.put("pig","小猪");
}
@Override
public String process(String request) {
return dict.getOrDefault(request,"无法翻译");
}
public static void main(String[] args) throws IOException {
UdpDicServer udpDicServer=new UdpDicServer(9090);
udpDicServer.start();
}
}