UDP协议(UDP协议特点 UDP的报文格式 UDP的服务端和客户端代码(简单的步骤))

目录

端口号 

UDP协议

UDP协议特点

UDP 无连接  

 UDP 面向数据报 

UDP 全双工  

UDP 的报文格式 

什么是校验和?

如何基于校验和来完成数据校验呢?

CRC算法(循环冗余算法) 

MD5算法/SHA算法(这里只介绍MD5算法(工作中常用))

UDP的服务端和客户端代码(简单的步骤例子) 

UDP的服务端 

UDP的客户端 

 


 

本篇主要介绍传输层(TCP/IP五层(或四层)模型)中的 UDP协议

想要详细了解UDP的内容,我们还需要了解一个概念 —— 端口号

端口号 

写一个服务器,必须手动指定一个端口号,通过端口来区分当前这个主机上的不同的应用程序;写一个客户端,当客户端在通信的时候也会有一个端口号(代码中感受不到),系统自动分配。 

端口号,固定就是占2个字节的 . 意味着,端口号表示的数据范围就是 0 ~ 65535(一般 0 不使用)

1~1023 称为 "知名端口号"

1024~65535 是我们普通的端口号

 "知名端口号" :就是给一些比较 ”知名“ 的服务器,预留一个 ”位置“,但事实上,这些所谓的 ”知名“ 服务器,现在大部分都已经不再使用了

其中几个,到现在仍然知名的端口:

22:ssh 服务器的端口号 (ssh协议是用来登录远程主机的)

80:http 服务器的端口号

443:https 服务器的端口号

......

 我们要确保使用的端口号和别人的端口号不要重复

介绍完端口号,我们就可以来介绍 UDP了

UDP协议

UDP协议特点

UDP :无连接,不可靠,面向数据报,全双工 

UDP 无连接  

UDP 协议本身不会存储对端的信息,要在发送数据的时候,显示指定要传输给谁

 

 

不可靠,代码中体现不出来

 

 UDP 面向数据报 

 UDP协议(UDP协议特点 UDP的报文格式 UDP的服务端和客户端代码(简单的步骤))_第1张图片

UDP 全双工  

通过一个socket,既可以 send,又可以 receive 

 

(最底下有完整的代码) 

 

UDP 的报文格式 

学习一个协议,其中最主要的工作就是理解协议的报文格式 

UDP协议(UDP协议特点 UDP的报文格式 UDP的服务端和客户端代码(简单的步骤))_第2张图片 

ps:源ip, 目的ip 在 网络层 

 

什么是校验和?

计算机中非常广泛使用的概念

前提:网络传输中,由于一些外部的干扰,就可能会出现数据传输出错的情况。

因此我们就要想办法,能够识别出出错的程序校验和,就是这样的一种检查手段。

校验和本质上是 一个字符串,体积比原始的数据更小,又是通过原始的数据生成的。

原始数据相同,得到的校验和就一定相同,反之,校验和相同,原始数据大概率相同(理论上存在不同的情况,但实际的概率非常低,忽略不计) 

如何基于校验和来完成数据校验呢?

1.发送方,把要发送的数据整理好 —— data1,然后通过一定的算法,计算出校验和 checksum1

2.发送方 把 data1 和 checksum1 一起通过网络发送出去

3.接收方收到数据,收到的数据称为 data2(此时的这个数据可能就和 data1 不一样了),还收到了checksum1

4.接收方再根据data2重新计算校验和(按照相同的算法),得到checksum2

5.对比 checksum1 和 checksum2 是否相同,如果不同,则认为data2 和 data1 一定不相同。如果相同,则认为 data1 和 data2 大概率是相同的(理论上存在不同的可能性,概率低,忽略)

 通过上面方式,就能发现数据传输出错

计算校验和,有很多种算法,此处UDP中使用的 CRC算法(循环冗余算法) 

 

CRC算法(循环冗余算法) 

就是把当前要计算 校验和 的数据的每个字节,都进行累加,把结果保存到这两个字节的变量中(累加过程中如果溢出了,也没关系)

如果中间某个数据,出现传输错误,第二次计算的 校验和 就会和第一次不同。

ps: CRC 这个算法其实不是特别靠谱,导致两个不同数据,得到相同的CRC校验和的概率比较大

(比如前一个字节恰好少个1,后一个字节恰好多个1,其实概率还是不大的,但确实有一定的风险) 

 

MD5算法/SHA算法(这里只介绍MD5算法(工作中常用))

 MD5算法 里有一系列的公式,来完成MD5的计算(咱们不需要考虑公式,这是给数学问题),但是咱们需要知道MD5 的特点

 MD5 的特点

1.定长:无论你原始数据多长,计算得到的MD5,都是固定长度 (这就很适配校验和,校验和就不应该太长,要不然不方便网络传输)

 

UDP协议(UDP协议特点 UDP的报文格式 UDP的服务端和客户端代码(简单的步骤))_第3张图片 

2.分散:给定两个原始 数据,哪怕绝大多数内容都一样,但只要有一个字节不同,得到的MD5值都会差异很大

UDP协议(UDP协议特点 UDP的报文格式 UDP的服务端和客户端代码(简单的步骤))_第4张图片 

UDP协议(UDP协议特点 UDP的报文格式 UDP的服务端和客户端代码(简单的步骤))_第5张图片  

3.不可逆:给你一个原始数据,计算MD5,非常容易,但是给你MD5,让你还原始数据,计算量非常庞大,以至于超出了现有计算机的算力极限,理论上是不可行的  

 

UDP的服务端和客户端代码(简单的步骤例子) 

UDP的服务端 

package network;

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

public class UdpEchoServer {
    // 创建一个 DatagramSocket 对象. 后续操作网卡的基础.
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {
        // 这么写就是手动指定端口
        socket = new DatagramSocket(port);
        // 这么写就是让系统自动分配端口
        // socket = new DatagramSocket();
    }

    public void start() throws IOException {
        // 通过这个方法来启动服务器.
        System.out.println("服务器启动!");
        // 一个服务器程序中, 经常能看到 while true 这样的代码.
        while (true) {
            // 1. 读取请求并解析.
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(requestPacket);
            // 当前完成 receive 之后, 数据是以 二进制 的形式存储到 DatagramPacket 中了.
            // 要想能够把这里的数据给显示出来, 还需要把这个二进制数据给转成字符串.
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            // 2. 根据请求计算响应(一般的服务器都会经历的过程)
            //    由于此处是回显服务器, 请求是啥样, 响应就是啥样.
            String response = process(request);
            // 3. 把响应写回到客户端.
            //    搞一个响应对象, DatagramPacket
            //    往 DatagramPacket 里构造刚才的数据, 再通过 send 返回.
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            // 4. 打印一个日志, 把这次数据交互的详情打印出来.
            System.out.printf("[%s:%d] req=%s, resp=%s\n", requestPacket.getAddress().toString(),
                    requestPacket.getPort(), request, response);
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(9090);
        server.start();
    }
}

UDP的客户端 

package network;

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

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp = "";
    private int serverPort = 0;

    public UdpEchoClient(String ip, int port) throws SocketException {
        // 创建这个对象, 不能手动指定端口.
        socket = new DatagramSocket();
        // 由于 UDP 自身不会持有对端的信息. 就需要在应用程序里, 把对端的情况给记录下来.
        // 这里咱们主要记录对端的 ip 和 端口 .
        serverIp = ip;
        serverPort = port;
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1. 从控制台读取数据, 作为请求
            System.out.print("-> ");
            String request = scanner.next();
            // 2. 把请求内容构造成 DatagramPacket 对象, 发给服务器.
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(serverIp), serverPort);
            socket.send(requestPacket);
            // 3. 尝试读取服务器返回的响应了.
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            // 4. 把响应, 转换成字符串, 并显示出来.
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);
        //UdpEchoClient client = new UdpEchoClient("42.192.83.143", 9090);
        client.start();
    }
}

 

 

 

 

你可能感兴趣的:(JavaEE,udp,网络协议,网络)