一.关于UDP
1.定义
UDP(User Datagram protocol),即用户数据报协议,是一种传输层协议
2.特点
(1)无连接性,使用UDP进行传输时,客户端与服务端不需要建立连接,而是通过对方的ip与端口号直接将数据传输过去
(2)不可靠性,使用UDP进行传输时,因为UDP的无连接性,客户端与服务端没有连接,所以客户端与服务端都无法知道自己的数据是否完整的成功被对方接收
(3)面向数据报,使用UDP进行传输时,数据的组织格式是数据报,它无法被拆分,即100个字节大小的数据报只能直接传输,而不能拆分成10个10字节的数据包依次传输
(4)全双工,使用UDP进行传输的时候,客户端与服务端都可以进行接收与发送操作,即都可以将数据发送给对方,也可以接收对方发送过来的数据
3.UDP协议的格式
(1)16位源端口号和16位目的端口号,后面UDP段还会封装上IP首部,形成IP数据报,IP与端口号配合,确定客户端与服务端的位置
(2)16位UDP长度,16位二进数表示的范围是0~65535,因此UDP段最大长度就是64kb(实际上64kb - 1,为了方便交流,常用64kb),除去头部占用的8个字节,因此UDP的数据载荷大小就是65527个字节,因为64kb与65527字节差不多,所以常说一个UDP段最大大小为64kb
(3)16UDP校验和,校验和用来检验数据传输是否出现错误,校验和是通过原始数据生成的字符串.假设A向B传输数据,如果数据在B时生成的校验和与数据在A生成的校验和相同时,则说明数据成功传输(有可能出现数据不同但校验和相同的情况,但是概率极低)
校验和的算法有:CRC算法,md5算法,sha1算法
4.基于UDP的应用层协议
(1) NFS(Network File System) : 网络文件系统
(2) TFTP(Trivial File Transfer Protocol) : 简单文件传输协议
(3) DHCP(Dynamic Host Configuration Protocol) : 动态主机配置协议
(4) BOOTP(Bootstrap Protocol) : 启动协议
(5) DNS(Domain Name System) : 域名解析协议
5.UDP与TCP的使用场景对比
UDP适用于对传输速度与实时性要求高,如视频,音频等
TCP适用于对数据可靠性与完整性要求高,,如文件传输,网络访问等
二.基于UDP的网络编程
1.所用到的API
(1)DatagramSocket API
(2)DatagramPacket API
(3)InetSocketAddress API
2.用UDP实现一个回响服务器
回响服务器可以实现将客户端发送过来的数据重新返回给客户端
代码如下
服务端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpEchoServer {
private DatagramSocket serverSocket = null;
//服务端构造方法
public UdpEchoServer (int port) throws SocketException {
this.serverSocket = new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服务端启动!");
while(true) {
System.out.println("等待客户端请求");
System.out.println("----------------------------------");
//创建请求数据报
DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
//用请求数据报来接收客户端的数据报
serverSocket.receive(requestPacket);
//将请求数据报中的内容转换为String
String request = new String(requestPacket.getData(),0,requestPacket.getLength());
//用process函数处理请求内容
String response = process(request);
//通过处理得到的结果来创建响应数据包
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress());
//发送响应数据包给客户端
serverSocket.send(responsePacket);
//打印本次相互通信的日志
System.out.printf("%s:%d req = %s, res = %s%n", responsePacket.getAddress().toString(), responsePacket.getPort(), request, response);
}
}
//进行数据返回
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
//指定一个端口号用来创建回响服务器,然后启动
UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
udpEchoServer.start();
}
}
客户端:
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UdpEchoClient {
private DatagramSocket clientSocket = null;
//记录服务端ip
private String serverIp = "";
//记录服务端端口号
private int serverPort = 0;
//客户端构造方法
public UdpEchoClient(String ip, int port) throws SocketException {
clientSocket = new DatagramSocket();
serverIp = ip;
serverPort = port;
}
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(serverIp),serverPort);
//发送请求数据包
clientSocket.send(requestPacket);
//创建响应数据报
DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
//接受响应数据报
clientSocket.receive(responsePacket);
//打印响应内容
System.out.println(new String(responsePacket.getData(),0,responsePacket.getLength()));
}
}
public static void main(String[] args) throws IOException {
//创建客户端,并启动客户端
UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);
udpEchoClient.start();
}
}
3.用UDP实现一个字典服务器
这里的字典服务器,可以借助于回响服务器的代码来创建
代码如下
服务端
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
public class UdpDictServer extends UdpEchoServer{
//用哈希表来模拟字典
private Map<String,String> dict = new HashMap<>();
//服务端构造方法
public UdpDictServer(int port) throws SocketException {
super(port);
dict.put("dog","小狗");
dict.put("cat","小猫");
dict.put("pig","小猪");
}
@Override
//重写回响服务器的process方法
public String process(String request) {
return dict.getOrDefault(request,"该词在字典中不存在");
}
public static void main(String[] args) throws IOException {
//指定端口创建服务器并启动
UdpDictServer server = new UdpDictServer(9090);
server.start();
}
}
客户端的代码不变
这里运用了java多态的特点,通过重写process方法,我们可以实现不同功能的服务器
谢谢阅读,如果觉得我的文章有用的话,请点个赞吧,有什么问题或者文章哪里写错,欢迎与我交流.