网络编程 - UDP协议

一,UDP基本概念

UDP协议在传输层,有几个重要的特性:

  1. UDP是无连接的:UDP想要进行通信,不需要征得对方的同意,只要在send方法中指定目标的地址(UDP自身是不会存储对端的信息的)
  2. UDP是不可靠传输:UDP没有安全机制,它只负责发送,至于接收端有没有收到,没有收到后怎么处理,它都不关心。(UDP的传输效率更高)
  3. UDP是面向数据报的:这里的数据报是数据传输的一个单位。
  4. UDP是全双工的:UDP可以实现双向通信

二,UDP协议端格式

这两个图一个意思。为什么没有源IP和目的IP,因为IP协议在网络层不在传输层。

源端口号和目的端口号讲过了,下面我们重点聊一聊什么是UDP长度和UDP校验和

2.1 UDP长度

UDP长度是两个字节,16位表示的数据,表示范围 0 ~ 65535 => 64kb,即UDP数据报最大就是64kb.

2.2 UDP校验和

在网络传输过程中,可能会出现一些外部干扰,就会导致数据传输出错(传输的数据内容出错)。这时就需要有方法来识别出错数据,而UDP校验和就是这样的一种检查方法。

校验和本质是一个字符串,是通过原始数据通过专门的算法生成的,但是体积比原始数据更小,如果原始数据相同,校验和一定相同,反之,校验和相同,原始数据大概率相同(理论上存在不同的可能性,但是概率极低,可忽略不计)

校验的过程:

1) 发送方把发送的数据整理好称为data1,通过专门的算法,计算出校验和sum1

2) 发送方把data1和sum1一起通过网络发送给接收方

3) 接收方把接受到的数据称为data2(由于干扰,可能数据出错),收到sum2(数据也可能出错)

4) 接收方根据data2按照相同的算法,计算出校验和sum3

5) 对比 sum2 和 sum3 是否相同,如果不同,则认为 data1 和 data2 一定不同。如果相同,则认为data1 和 data2 大概率相同(理论上存在不同的可能性,但是概率极低,工程上忽略不计)

UDP协议中使用CRC算法(循环冗余算法)来计算校验和:把当前计算校验和的数据,每个字节都进行累加,把结果保存到UDP校验和中,如果数据溢出也没关系,如果中间某个数据传输错误,第二次计算的校验和与第一次不同。但是可能出现前一个字节恰好少1,后一个字节恰好多1这种类似的情况,虽然概率不大,但是还是会出现这种情况。

介绍一种更加保险更加常见的算法:md5

1)定长:md5的长度是固定的,无论你的数据有多长,计算出的md5都是固定的

2)分散:给定两个原始数据,哪怕绝大部分内容相同,但只要有一个字节不同,得到的md5值的差异也会很大

3)不可逆:给你一个md5值,要你还原出原始数据,由于计算量过于庞大,已经突破现有的算力极限,理论上是不可能的

三,UDP中的Socket api

Socket API 是系统提供的一组用于网络编程的应用程序接口,socket 本质上是一种特殊的文件,它是把网卡这个设备,给抽象成了文件,往socket文件中写数据,就相当于是通过网卡发送数据,从socket文件中读数据,就相当于通过网卡接收数据。

在 JAVA 中使用 DatagramSocket 这个类来表示系统内部 socket 文件。使用 DatagramPacket 这个类来表示UDP数据报。

3.1 DatagramSocket

|--------------------------------|-----------------------------|
| 方法名 | 说明 |
| DatagramSocket() | 创建一个Socket,绑定到本机任意一个没人使用的端口 |
| DatagramSocket(int port) | 创建一个Socket,绑定port端口 |
| void receive(DatagramPacket p) | 接收数据报p |
| void send(DatagramPacket p) | 发送数据报p |
| void close() | 关闭Socket |

3.2 DatagramPacket

|----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
| 方法名 | 说明 |
| DatagramPacket(byte[] buf, int length) | 构造一个DatagramPacket以用来接收数据报,接收的数据保存在 字节数组(第一个参数buf)中,接收指定长度(第二个参数 length) |
| DatagramPacket(byte[] buf, int offset, int length,SocketAddress address) | 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数 length)。address指定目的主机的IP和端口号 |
| getAddress() | 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址 |
| int getPort() | 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号 |
| byte[] getData() | 获取数据报中的数据 |

四,使用UDP实现客户端和服务器

4.1 回显服务器

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

//回显服务器UDP
public class Server {
    private DatagramSocket socket = null;
    public Server(int port) throws SocketException {
        socket = new DatagramSocket(port);//端口号
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            //1.读请求
            DatagramPacket request = new DatagramPacket(new byte[1024],1024);
            socket.receive(request);//如果没有请求,就阻塞
            String r = new String(request.getData(),0,request.getLength());//得到真实长度
            //2.根据请求计算响应
            String response = process(r);
            //3.返回响应
            DatagramPacket res = new DatagramPacket(response.getBytes(),
                    response.getBytes().length,request.getSocketAddress());
            // response.length()得到字符长度,response.getBytes().length得到字节长度
            // 网络传输以字节为单位进行操作
            socket.send(res);
            //4.打印日志
            System.out.printf("[%s:%d] req=%s,res=%s\n",
                    request.getAddress().toString(),request.getPort(),r,response);
            //为什么不close()?
            //socket是文件描述符表中的一个表象,因为我们不使用socket时,进程就要关闭,资源就全部释放了
        }
    }
    public String process(String request){
        return request;
    }
    public static void main(String[] args) throws IOException {
        Server server = new Server(9090);
        server.start();
    }
}

4.2 回显客户端

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class Client {
    private DatagramSocket socket = null;
    private String serverIP = "";
    private int serverPort = 0;
    public Client(String ip, int port) throws SocketException {
        socket = new DatagramSocket();
        //UDP不会存储对端的信息,需要在应用程序中把对端的信息记录下来
        this.serverIP = ip;
        this.serverPort = port;
    }

    public void start() throws IOException {
        System.out.println("客户端请启动");
        Scanner scanner = new Scanner(System.in);
        while(true){
            //1.输入请求
            System.out.print("-> ");
            String req = scanner.next();
            //2.发给服务器
            DatagramPacket request = new DatagramPacket(req.getBytes(),req.getBytes().length,
                    InetAddress.getByName(serverIP),serverPort);
            socket.send(request);
            //3.获取响应
            DatagramPacket res = new DatagramPacket(new byte[1024],1024);
            socket.receive(res);
            //4.显示响应
            String response = new String(res.getData(),0,res.getLength());
            System.out.println(response);
        }
    }
    public static void main(String[] args) throws IOException {
        Client client = new Client("10.162.153.3",9090);
        client.start();
    }
}
相关推荐
写bug的小屁孩23 分钟前
websocket身份验证
开发语言·网络·c++·qt·websocket·网络协议·qt6.3
chenjingming66632 分钟前
网络技术-定义配置ACL规则的语法和命令
网络
Dynadot_tech1 小时前
使用API有效率地管理Dynadot域名,列表形式查看账户whois联系人信息
网络·api·域名注册·dynadot
网安-轩逸2 小时前
【网络安全】身份认证
网络·安全·web安全
石牌桥网管2 小时前
OpenWrt广播DNS到客户端
网络·openwrt
想成为高手4992 小时前
网络基础概念与应用:深入理解计算机网络
网络·计算机网络
Aiden_SHU3 小时前
Wireshark中的length栏位
服务器·网络·wireshark
叫我龙翔4 小时前
【计网】实现reactor反应堆模型 --- 多线程方案优化 ,OTOL方案
linux·运维·网络
?crying4 小时前
蓝队基础4 -- 安全运营与监控
网络·安全·web安全
茶颜悦色vv5 小时前
蓝队知识浅谈(中)
网络·web安全·网络安全