前言
UDP是一个高效、快速、简单的传输协议,适合于需要低延迟和实时性的应用
本篇将介绍UDP相关的api,并使用UDP构建回显服务器程序。
一.UDP与TCP
特点
UDP:无连接,不可靠,面向数据报,全双工。
TCP:有连接,可靠,面向字节流,全双工。
何为连接?
此处所说的连接是抽象的连接,并不是实际两根线的相连,是指通信双方是否保留对方的信息(如IP地址,端口号)。
UDP是无连接的,通信双方不会保留对方的地址。
TCP是有连接的,通信双方保留着对方的地址。
何为可靠?
可靠指的是通信双方是否关注信息正确的传递到对方手上,可靠指会尽可能的确保数据传输到对方,不可靠是不关心数据是否传输过去。
UDP是不可靠的,指的是当通信出现问题时,会直接把数据包丢弃,不会进行重传。
TCP是可靠的,指通信出现问题时,有着应答响应和延时重传机制,防止数据的丢失
面向数据报与面向字节流
两种协议的传输单位不同。
数据报是一种专门为网络通信传输构造的特殊结构的传输单位,将需要传输的数据打包成一个整体。
UDP协议传输时,以一整个数据报为单位进行传输。
TCP协议面向字节流指的是数据被视为一个连续的字节序列,发送 方将数据拆分为字节流发送,而接收方将这些字节流重新组装成原始数据
全双工与半双工
全双工:一个通信信道,可以双向通信(既可以发送数据,也可以同时接收数据)
半双工:只能单向通信(接收数据与发送数据不能同时发送)
二.UDP的常用api
对于UDP来说,主要提供了两个核心api,即DatagramSocket和DatagramPacket(相当于网卡的遥控器)
1.DatagramSocket
1)构造方法
方法签名 | 方法说明 |
DatagramSocket() | 创建⼀个UDP数据报套接字的Socket,绑定到本机任意一个 随机端口(一般用于客户端) |
DatagramSocket(int port) | 创建⼀个UDP数据报套接字的Socket,绑定到本机指定的 端口(一般用于服务器) |
2)DatagramSocket方法
方法签名 | 方法说明 |
void receive(DatagramPacket) | 从此套接字接收数据报(如果没有接收到数据报,该⽅法会阻塞等待) |
void send(DatagramPacket) | 从此套接字发送数据报包(不会阻塞等待,直接发送) |
void close() | 关闭此数据报套接字 |
2.DatagramPacket
1.构造方法
方法签名 | 方法说明 |
DatagramPacket(byte[] buf, int length) | 构造⼀个DatagramPacket以⽤来接收数据报,接收的数据保存在字节数组(第⼀个参数buf)中,接收指定⻓度(第⼆个参数length) |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) | 构造⼀个DatagramPacket以⽤来发送数据报,发送的 数据为字节数组(第⼀个参数buf)中,从0到指定⻓度(第⼆个参数length)。address指定⽬的主机的IP 和端⼝号 |
2.DatagramPacket方法
方法签名 | 方法说明 |
InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址 |
int getPort() | 从接收的数据报中,获取发送端主机的端⼝号;或从发送的数据报中,获取接收端主机端⼝号 |
byte[] getData() | 获取数据报中的数据 |
当看方法,可能看的云里雾里,接下来通过代码来演示
三.UDP服务器端实现
1.代码实现
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpService {
private DatagramSocket socket = null;
public UdpService(int port) throws SocketException {
socket = new DatagramSocket(9090);
//参数是服务器绑定的端口
}
public void start() throws IOException {
System.out.println("服务器开始运行");
while (true) {
//服务器需要反复的执行客户的请求
DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
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());
socket.send(responsePacket);
System.out.printf("[%s:%d],服务器响应:%s,客户机请求:%s", requestPacket.getSocketAddress(),
response, request);
}
}
public String process(String request) {
return request;
//回显服务器,返回请求,不做其他操作
}
public static void main(String[] args) throws IOException {
UdpService service=new UdpService(9090);
service.start();
}
}
2.代码解析
服务器的基本流程主要分为3个部分
1)读取请求并解析
DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
socket.receive(requestPacket);
String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
此段代码中,首先定义requestPacket数据报,确定数据报的大小,再接收客户端请求,放入数据报中,并解析请求信息。
2)根据请求计算响应【服务器最重要的环节】
String response = process(request);
public String process(String request) {
return request;
//回显服务器,返回请求,不做其他操作
}
此代码实现的为回显服务器,将请求作为响应返回,不涉及其他逻辑
3)把响应写回给客户端,打印日志
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
requestPacket.getSocketAddress());
socket.send(responsePacket);
System.out.printf("[%s:%d],服务器响应:%s,客户机请求:%s", requestPacket.getSocketAddress(),
response, request);
定义responsePacket数据报,将response的信息打包好,定义好发送的ip地址和端口号,用send发送回客户端,并打印出客户端的ip 端口 请求信息和响应信息。
四.UDP客户端实现
1)代码实现
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UdpCilent {
private DatagramSocket socket=null;
private String ServiceIP;
private int ServicePort;
public UdpCilent(String serviceIP,int servicePort) throws SocketException {
this.ServiceIP=serviceIP;
this.ServicePort=servicePort;
socket=new DatagramSocket();
}
public void start() throws IOException {
System.out.println("客户端启动");
Scanner scanner=new Scanner(System.in);
while (true){
System.out.println("->");
String request= scanner.next();
DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(this.ServiceIP),
this.ServicePort);
socket.send(requestPacket);
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 {
UdpCilent cilent=new UdpCilent("127.0.0.1",9090);
cilent.start();
}
}
2)代码解析
1)从控制台中输入指令,将指令打包成数据报,数据报中要指明服务器的ip地址和端口号,才能将数据发送给对应的服务器处理
public class UdpCilent {
private DatagramSocket socket=null;
private String ServiceIP;
private int ServicePort;
public UdpCilent(String serviceIP,int servicePort) throws SocketException {
this.ServiceIP=serviceIP;
this.ServicePort=servicePort;
socket=new DatagramSocket();
}
public void start() throws IOException {
System.out.println("客户端启动");
Scanner scanner=new Scanner(System.in);
while (true){
System.out.println("->");
String request= scanner.next();
DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(this.ServiceIP),
this.ServicePort);
socket.send(requestPacket);
2)定义响应数据报,接收服务器处理完数据后的响应,并打印出来。
DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
socket.receive(responsePacket);
String response=new String(responsePacket.getData(),0,responsePacket.getLength());
System.out.println(response);
3)启动程序,在new 对象中填入服务器的ip与端口号。
public static void main(String[] args) throws IOException {
UdpCilent cilent=new UdpCilent("127.0.0.1",9090);
cilent.start();
}
五.服务器与客户端执行过程
1.执行流程
1)首先控制台输入指令,客户端发送请求到服务器。
2)紧接着,服务器接收到请求,解除阻塞
3)服务器把得到的数据构造成string,执行process()方法对数据进行操作,返回操作结果response,并打包成数据报发送会客户端
4)客户端收到了返回的响应后,解除阻塞
5)打印日志,进入下一次循环
2.字典服务器
字典服务器提供着将客户端输入的英文转化中文,只需继承UDP服务器,并重写proces方法即可实现。
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
public class DictService extends UdpService{
private Map<String,String> dict=new HashMap<String,String>();
public DictService(int port) throws SocketException {
super(port);
dict.put("cat","猫");
dict.put("dog","狗");
dict.put("duck","鸭子");
dict.put("fish","鱼");
}
@Override
public String process(String request) {
return dict.getOrDefault(request,"未知单词");
}
public static void main(String[] args) throws IOException {
DictService servicer=new DictService(9090);
servicer.start();
}
以上便是全部内容,如有不对,欢迎指正
标签:UDP,DatagramPacket,String,request,编程,Javaee,服务器,new,public From: https://blog.csdn.net/yc_xym/article/details/143043164