【JavaEE】网络编程之UDP套接字

news2024/12/22 23:23:42

目录

1、网络编程基础

2、UDP数据报套接字编程 

2.1.DatagramSocket  API(方法)

2.2、DatagramPacket  API(方法) 

2.3、InetSocketAddress  API  

3、基于UDP socket写一个回显服务器

3.1、服务器端

3.2 、客户端

3.3、完整回显服务器和客户端代码

3.3.1、服务器和客户端代码的执行流程


1、网络编程基础

我们知道网络通信的过程中,发送方将数据从应用层封装到物理层,然后进行发送。接收方在拿到数据之后,将数据从物理层分用到应用层。我们进行网络编程就是将网络上的主机,通过不同的进程,以编程的方式实现网络通信。进行网络编程,我们主要可以操作的就是应用层,其他层都是系统封装好的,我们没有能力去修改。我们要发送一个数据,需要上层协议,调用下层协议,也就是说我们在进行应用层代码编写的时候,需要调用传输层给我们提供的API。这组API我们将其统称为socket api.系统提供的socket api有很多,我们主要了解下面这两组。

由于TCP和UDP这两个协议的差别很大,所以提供的API也存在很大的差异。了解一下这两个协议最基本的特点。

UDP特点TCP特点
无连接有连接
不可靠传输可靠传输
面向数据报面向字节流
全双工全双工
  • 有连接和无连接:有连接可以理解为,通信双方,各自记录了对方信息,表示两台主机在进行通信的时候是否需要记录一下对端的信息。 使用UDP通信的双方,不需要保存对端的相关信息。使用TCP通信的双方,则需要保存对方的相关信息。(使用UDP通信,不需要接受连接,直接投递,就能通信。可以想象一下发短信;使用TCP通信,需要先把链接接收,才能通信。可以想象一下打电话)。
  • 可靠传输与不可靠传输:这里的可靠传输和不可靠传输并不是说安全性的问题,而是说发送端在将数据发送了之后,发送端能不能判断接收端收到信息,如果能够确定接收端收到了信息或者没有接收到消息,这就是可靠传输。不可靠传输就是,发送端将数据发送之后,就不会在管了,至于接收方接收到消息还是没有接收到消息,发送端不关心。
  • 面向字节流和面向数据报:面向字节流就是以字节为传输的基本单位,以流的形式传输数据,可以一次读一个字节,也可以一次读很多字节,读写方式非常灵活。面向数据报就是以一个UDP数据报为基本单位。
  • 全双工和半双工:全双工是一条通信链路,双向通信(就像车道一样)。半双工是一条通信链路,单向通信。

2、UDP数据报套接字编程 

UDP数据报的套接字提供了最主要的两个核心类、一个是DatagramSocket一个是DatagramPacket。

2.1.DatagramSocket  API(方法)

Datagram的意思就是"数据报",Socket,说明这个对象是一个socket对象(相当于对应到系统中一个特殊的文件【socket文件】)。socket文件并非对应到硬盘上的某个数据存储区域,而是对应到网卡这个硬件设备。

我们想要进行网络通信,就需要有socket文件这样的对象,借助这个socket文件对象,才能够间接的操作网卡。这个socket对象就像是一个遥控器。往这个socket对象中写数据,相当于通过网卡发送消息。从这个socket对象中读数据,相当于通过网卡接收消息。

理解:我们在看电视的时候,按遥控器的按钮就相当于给socket对象中写数据,电视机根据接收到的信号,显示对应的画面。电视机显示相应的画面这就相当于网卡对外发送消息。同理从socket对象中读数据我们反着理解 电视机和遥控器的关系。电视机显示一个画面,如果遥控器上有显示屏,那么我们就能看到电视上这个画面对应着遥控器上我们按过的数据。

✨ DatagramSocket类的构造方法:

下面我们提供了两个构造方法一个带参数,一个不带参数,带参数的构造方法中的参数代表的意思就是端口号

方法方法说明
DatagramSocket()创建一个UDP数据报套接字Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(int port)创建一个UDP数据报套接字Socket,绑定本机指定的端口(一般用于服务端 )

第二个带有参数的构造方法可能会被用户端或者服务器都使用,服务器端的socket对象往往都要关联一个具体的端口号。客户端的socket对象则不需要手动指定,系统会自己分配。

✨DatagramSocket方法:

方法方法说明
void receive(DatagramPacket p)从次套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

2.2、DatagramPacket  API(方法) 

✨DatagramPacket构造方法:

第一个构造方法,不需要设置地址进去,通常用来接收消息;

第二个构造方法,需要显示的设置地址进去,通常要用来发送消息。

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

✨ DatagramPacket方法:

方法方法说明
InetAddressgetAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[ ] getData()获取数据报中的数据 

构造UDP发送的数据报时,需要传入socketAddress,该对象可以使用InetSocketAddress来创建。

2.3、InetSocketAddress  API  

✨InetSocketAddress(SocketAddress的子类)构造方法:

方法方法说明
InetSocketAddress(InetAddress addr,int port)创建一个Socket地址,包含IP地址和端口号

3、基于UDP socket写一个回显服务器

基于UDP socket写一个最简单的客户端-服务器程序。

3.1、服务器端

回显服务器:客户端发送一个请求,服务端返回一个一摸一样的响应。就比如我们去吃饭,给老板说来一份蛋炒饭,老板没有给你做,他也说了一句老板来一份蛋炒饭。

✨一个服务器,主要做三个核心工作:

  1. 读取请求并解析
  2. 根据请求计算响应(会先服务器就是把这里省略掉了)
  3. 把响应返回到客户端

1️⃣创建一个UDP的socket对象并且指定一个端口号

public class UdpEchoServer {
    //需要先定义一个socket对象
    //通过网络通信,必须要使用socket对象
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {
        //构造socket的同时,指定要关联/绑定的端口。
        socket = new DatagramSocket(port);
    }

 我们创建的服务器这个类中构造的socket对象,绑定端口号的时候时会提示要申明异样,这是因为,我们在主方法中创建服务器这个对象并手动指定端口号的时候,我们指定的端口号,可能被其他的进程占用着,这个时候这里的绑定端口号的操作就会出错。(同一个主机上,一个端口,同一时刻只能被一个进程绑定)。

2️⃣启动服务器

        //启动服务器的主逻辑
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            //每次循环,要做三件事情
            //1.读取请求并解析
                //构造一个空饭盒
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //receive 方法会从网卡中读取数据填充到requestPacket对象中。
            socket.receive(requestPacket);
            //为了方便处理这个请求,把数据报转换成String
            String request = new String(requestPacket.getData(),0, requestPacket.getLength());
            //2.根据请求计算响应(此处省略这个步骤)
            //3.把响应结果写回到客户端

        }
    }
}

 启动服务器之后,服务器会做三件事情,1读取请求并解析,2.根据请求计算响应,3.把响应结果写回到客户端。服务器不可能只是对一个客户端进行响应,所以这里使用where循环,当服务器对一个客户端服务完成之后,他还需要在对其他客户端的请求做出响应。

❓看到这里有的老铁会想socket对象怎样存储客户端发来的请求数据呢?


  1. 我们在用户态中写一个应用程序,在其中创建了一个socket对象,此时的socket对象在内核中对应了一个PCB(进程控制块),PCB中存在一个文件描述表(记录这个程序打开了那些文件),这个文件描述符表中有一个项,就记录了这个打开的socket文件。socket文件和网卡建立了链接之后,网卡接收到数据之后,对数据报分用到传输层,看到端口号,根据端口号,就找到了对应的进程(也就找到了对应的socket文件)。
  2. 系统内核,会给每个socket文件都分配一定的内存空间分为:1.发送缓冲区,2.接收缓冲区。
  3. 系统会把收到的这个数据拷贝到该socket对应的接收缓冲区中,此时应用程序调用socket.receive方法,就是从该内核中的socket文件的接收缓冲区里把数据拷贝到了receive方法参数中的DatagramPacket对象中。(socket文件的接收缓冲区类似于阻塞队列,receive方法将该缓冲区中内容拷贝到DatagramPacket对象中,就相当于数据出队列)

 补充:

❓❓网卡属于TCP/IP五层协议的那一层?


❗❗如果精确的收,网卡的位置当时应该算是物理层,单网卡时PC与Internet网云连接的通道,因而,IP层也存在并且最重要的也出现在IP层,因此,如果单一的说,网卡在TCP/IP的第二层比较正确。(这也就能解释为什么上述网卡得到数据之后,可以分用到传输层)。

✨理解socket对象调用的receive方法

  • receive这个方法的参数是一个输出型参数。
  • 之前我们在Java中看到的多数方法都是,使用参数作为方法的"输入",使用返回值作为方法的输出。比如我们要调用一个方法找到两数的最小值,这个时候我们就会调用Math类的min方法并输入两个参数,比较完成之后,方法通过return将结果输出。
  • 但是这里的receive方法是传入一个空的packet对象,然后由receive方法内部把参数的这个packet进行填充,等到这个方法执行完毕,packet对象内部也就有了写回的数据。

举例理解:输出型参数,就像是我们去餐厅吃饭,自己拿了一个餐盒,将空餐盒交给打饭阿姨,阿姨把饭打好之后给我们。

画图理解

❗❗❗注意:服务器启动之后,调用start方法,就会立即执行到receive这里,要是此时还没有客户端发来数据,此时receive就会阻塞,一直持续到客户端有请求数据发送过来。

✨理解将请求的数据报转换成为String 

这个操作并非是必须的,只是此处为了后续的代码简单,当客户端发来的数据是"老板来一份蛋炒饭",此时这个数据就会以二进制的形式存在于requestPacket中的字节数组中,把字节数组中的元素拿出来构造成一个String,这个String内容就是"老板来一份蛋炒饭"。

🎉offest:0和requestPacketgetLength()这两个参数的的意义:

requestPacket对象中的byte数组给定的数组长度为4096,但是一个请求数据并没有将这个数组占满,我们构造String时,通过requestPacket.getLength()方法求出请求数据的实际长度。

这两个参数表示的意思为:从byte[ ] 的0下标位置到getLength()这个下标,把这一段用来构造字符串(String)。

3️⃣根据请求计算响应

    //2.根据请求计算响应(此处省略这个步骤)
    String response = process(request);
    //这个方法希望是分局请求来计算响应
    //由于我们写的是回显程序,所以请求是啥,响应就是啥
    //如果后续写一个别的服务器,不在回显,具有具体的业务,可以修改process方法,
    //根据需要来重新构造响应
    private String process(String request) {
        return request;
    }

4️⃣把响应写回到客户端

这里有两步操作,1、打包响应,2、发送响应

            //3.把响应结果写回到客户端
                 //和请求的数据报不同,此处构造响应的时候,需要指定这个报要发给谁
                //根据response字符串,构造一个DatagramPacket对象(响应的数据报)
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                   //requestPacket是从客户端这里收来的,getSocketAddress 就会得到客户端的ip和端口
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
                //打印日志
            System.out.printf("[%s:%d] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);

       
    

我们首先要构造一个响应的数据报,这个数据报中存有根据请求数据计算得出的响应。

  • getBytes()方法的作用是使用idea默认的字符集将此String编码为字节序列,并将结果存储到新的字节数据中。
  • 构造UDP发送的数据报时,需要传入socketAddress,该对象可以使用InetsocketAddress来创建。requestPacket.getSocketAddress()这个操作的作用是,从请求数据报中获取这个响应发送的主机地址。

 


3.2 、客户端

1️⃣创建一个UDP的socket对象

这里我们创建客户端类的时候,如果需要进行网络通信,也需要创建一个socket对象(文件),写这个客户端类的构造方法的时候,我们并不需要显示的关联一个端口号,这并代表客户端没有端口,而是让系统自己分配一个空闲的端口。我们在创建客户端类的时候是需要创建客户端IP和客户端端口的成员变量。因为客户端启动的时候要知道服务器在哪里。

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;
    //客户端启动,需要知道服务器在哪里
    public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
        //对于客户端来说,不需要显示关联端口
        //这并不代表客户端没有端口,而是让系统自动分配空闲的端口
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

2️⃣启动客户端

启动客户端这个方法中存在四个步骤:

  1. 先从控制台,读取一个字符串
  2. 把字符串构造成UDP数据报,并进行发送
  3. 客户端尝试读取服务器返回的响应
  4. 把响应数据转换成字符串(string)显示出来
    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(serverIP),serverPort);
           socket.send(requestPacket);
            //3.客户端尝试读取服务器返回的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            //4.把响应数据转换成String显示出来
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.printf("req: %s,resp: %s\n",request,response);
        }
    }

✨理解把字符串构造成UDP数据报。

这里将输入的字符串转换成UDP数据报,需要进行两方面的操作,一方面首先将字符串编码为字节序列,存入新的字节数组中;另一方面需要指定服务器的IP和端口号。

 DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIP),serverPort);
  • getBytes()方法:使用idea默认的字符集将此String编码为字节序列,并将结果存储到新的字节数据中。
  • InetAddress.getBytes(serverIP):设置这个数据报要发送给服务器的主机网络地址(目的主机的IP)。
  • serverPort:表示设置一个端口号(这个端口号表示服务器在执行的时候绑定的那个端口号)

这里对用户输入的字符串进行转换封装成数据报对服务器发送的时候,我们需要设置服务器的主机IP和服务器程序执行所绑定的端口号。

3.3、完整回显服务器和客户端代码

🎉服务器

public class UdpEchoServer {
    //需要先定义一个socket对象
    //通过网络通信,必须要使用socket对象
    private DatagramSocket socket = null;

    //绑定一个端口,不一定成功,会抛出异常,所以这里需要先申明这个异常
    //如果某个端口已经被别的进程占用了,此时这里的绑定操作就会出错
    //同一个主机上,一个端口,同一时刻只能被一个进程绑定
    public UdpEchoServer(int port) throws SocketException {
        //构造socket的同时,指定要关联/绑定的端口。
        socket = new DatagramSocket(port);
    }
    //启动服务器的主逻辑
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            //每次循环,要做三件事情
            //1.读取请求并解析
                //构造一个空饭盒
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //receive 方法会从网卡中读取数据填充到requestPacket对象中。
            socket.receive(requestPacket);
            //为了方便处理这个请求,把数据报转换成String
            String request = new String(requestPacket.getData(),0, requestPacket.getLength());
            //2.根据请求计算响应(此处省略这个步骤)
            String response = process(request);
            //3.把响应结果写回到客户端
                //和请求的数据报不同,此处构造响应的时候,需要指定这个报要发给谁
                //根据response字符串,构造一个DatagramPacket对象(响应的数据报)
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                   //requestPacket是从客户端这里收来的,getSocketAddress 就会得到客户端的ip和端口
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
                //打印日志
            System.out.printf("[%s:%d] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);

        }
    }
    //这个方法希望是分局请求来计算响应
    //由于我们写的是回显程序,所以请求是啥,响应就是啥
    //如果后续写一个别的服务器,不在回显,具有具体的业务,可以修改process方法,
    //根据需要来重新构造响应
    private String process(String request) {
        return request;
    }

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

 🎉客户端

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;
    public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
        //对于客户端来说,不需要显示关联端口
        //这并不代表客户端没有端口,而是让系统自动分配空闲的端口
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }
    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(serverIP),serverPort);
           socket.send(requestPacket);
            //3.客户端尝试读取服务器返回的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            //4.把响应数据转换成String显示出来
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.printf("req: %s,resp: %s\n",request,response);
        }
    }
    public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);
        udpEchoClient.start();
    }
}

3.3.1、服务器和客户端代码的执行流程

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/611908.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习常识 21: 卷积神经网络

摘要: 卷积操作保留体现了空间相关性. 1. 卷积操作 图 1. 卷积操作 Valid 方式. 图 1 下平面标定的 3 3 3 \times 3 33 区域, 对应于个 3 3 3 \times 3 33 卷积, 这 9 9 9 个数对应着相乘, 然后相加, 获得了上平面标定的 1 1 1 个小区域的值. 注意这里不是矩阵的乘法. 卷…

《大数据技术与应用》课程实验报告|week12|实验8|Pig——高级编程环境 验证评估函数

目录 一、实验内容 二、实验目的 三、实验设备 四、实验步骤 步骤一 步骤二 步骤三 步骤四 步骤五 步骤六 步骤七 步骤八 步骤九 步骤十 步骤十一 步骤十二 步骤十三 步骤十四 步骤十五 步骤十六 五、实验结果 六、实验小结 一、实验内容 验证19.5节中的…

Apache网页的日志分割与优化

Apache网页的日志分割与优化 一、日志分割的作用二、rotatelogs 分割1.修改apache服务的主配置文件2.创建分割日志保存目录3.浏览器访问 三、AWStats 分析系统1.将安装AWStats 所需软件包传到/opt目录下2.安装 AWStats 软件包3.为要统计的站点建立配置文件4.修改自动生成的 aws…

电表的698通信协议

原文连接:https://blog.csdn.net/ss86655/article/details/109997891 该协议规定了用电信息的数据交换过程,一般用于主站与电能表之间、终端与电能表之间的数据交换,主站与终端一般用不同的客户机地址来区分。1、通信架构 有两种方向的数据…

linux系统中代码突然无法执行,没有权限访问文件,但是可以在文件管理器中查看文件

前言 这段时间遇到了一个非常离谱的问题,我的只要设计移动硬盘中数据的所有代码突然无法运行,我折腾了很久一直觉得是移动硬盘坏了,但拿到其他电脑上去是可以运动的。今天终于偶然发现了问题。 直接说结论: 移动硬盘的挂载点变了…

SQL-DML、DQL查询数据

SQL-DML、DQL查询数据 1 DML DML主要是对数据进行增(insert)删(delete)改(update)操作。 1.1 添加数据 给指定列添加数据 INSERT INTO 表名(列名1,列名2,…) VALUES(值1,值2,…);给全部列添加数据 INSERT…

MySQL数据库性能优化技巧介绍

MySQL是目前最流行和广泛使用的开源关系型数据库之一,随着数据量的增长和访问负载的提高,优化数据库性能变得至关重要,以确保系统能够高效地处理大量的并发请求。本文将记录一些MySQL数据库性能优化的技巧,提高数据库的运行效率&a…

程序员——应届生毕业,竟有20k高薪岗位?!

马士兵优极限训练营让我在技术和个人能力上都有了很大的提升。在未来的职业生涯中,我会继续努力,不断学习和成长,为自己和社会做出更大的贡献 01 选择大数据 只因更有前景 我是计算机专业出身,但是在大学的时候我对大数据行业更…

vue3 ---- 递归组件生成menu菜单 路由守卫鉴权

目录 递归组件​ el-menu 父组件 子组件 路由 Vue路由守卫实现登录鉴权 全局守卫 路由独享的守卫 组件内的守卫 完整的导航解析流程 对于一些有规律的DOM结构,如果我们再一遍遍的编写同样的代码,显然代码是比较繁琐和不科学的,而且…

5个有效方法教你如何正确使用云渲染,防错必备!

随着技术的进步和计算能力的提升,云渲染成为了现代计算机图形学和动画制作中不可或缺的一环。无论是在电影、游戏还是建筑可视化等领域,渲染图像的质量和效率都对最终结果有着巨大的影响。然而,云渲染也面临着一些潜在的问题,如渲…

一文看懂B TREE和B+TREE数据结构实现过程及数据存储结构

概述 一文看懂B TREE和BTREE数据结构实现过程及数据存储结构 一、B tree数据结构实现过程 这里有一个陌生区关于 Max. Degree,这个你可以理解为阶,也可以理解为度,即B 树的阶数(一个节点存储的键的数量) 这里有一个陌生区关于…

简单上手!快速将另一个报表的页面添加到 FastReport .NET!

FastReport 是功能齐全的报表控件,可以帮助开发者可以快速并高效地为.NET,VCL,COM,ActiveX应用程序添加报表支持,由于其独特的编程原则,现在已经成为了Delphi平台最优秀的报表控件,支持将编程开…

ROS:古月居第一次作业(话题与服务编程、动作编程、TF编程)

一.话题与服务编程 话题与服务编程:通过代码新生一只海龟,放置在(5,5)点,命名为“turtle2”;通过代码订阅turtle2的实时位置并打印在终端;控制turtle2实现旋转运动; demo_turtle.l…

智能出行更安全,亚马逊云科技携手木卫四助汽车客户安全合规出海

木卫四(北京)科技有限公司在汽车网络安全领域拥有独特专业知识,其融合人工智能算法的安全检测引擎可以不依赖车辆中安装的代理软件,只需几周即可快速部署实施,是汽车网络安全领域的技术领先者。 在亚马逊云科技初创团…

消息中间件之ActiveMq安装

文章目录 前言安装下载地址安装 使用控制台调整配置文件 前言 2023年年中了,又遇到了老朋友activeMq,上次接触activeMq还是在15年的时候,系统中用到了这个消息中间件。 阔别8年之久,竟然又用到了这个老家伙! 安装 要…

【6.05 代随_48day】 打家劫舍、打家劫舍 II、打家劫舍 III

打家劫舍、打家劫舍 II、打家劫舍 III 打家劫舍1.方法图解步骤代码 打家劫舍 II1.方法代码 打家劫舍 III图解步骤代码 打家劫舍 力扣连接:198. 打家劫舍(中等) 1.方法 确定dp数组(dp table)以及下标的含义 dp[i]&am…

如何利用 Electron 快速开发一个桌面端应用

前言 一直以来都有听说利用electron可以非常便捷的将网页应用快速打包生成为桌面级应用,并且可以利用 electron 提供的 API 调用原生桌面 API 一些高级功能,于是这次借着论证环信 Web 端 SDK 是否可以在 electron 生成的桌面端正常稳定使用,…

基于国产器件的KCF跟踪算法实现与验证

在国产的FT-M6678 DSP上实现KCF算法是我研究生期间的主要工作,KCF算法的原理与实现已经在之前的文章以及我的Gitee仓库中有部分介绍。这里主要介绍DSP与上位机通信的方式,以及XDMA Linux驱动的使用。具体的设计细节可以看我的毕业设计补充材料。 SRIO与…

SpringBoot 使用validator进行参数校验(实例操作+注意事项+自定义参数校验)

一、实例操作 ①、引入依赖 <dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>6.0.4.Final</version></dependency> ②、创建实体类 package com.springboot.entity;im…

蓝桥杯2022年第十三届决赛真题-出差

题目描述 A 国有 N 个城市&#xff0c;编号为 1 . . . N。小明是编号为 1 的城市中一家公司的员工&#xff0c;今天突然接到了上级通知需要去编号为 N 的城市出差。 由于疫情原因&#xff0c;很多直达的交通方式暂时关闭&#xff0c;小明无法乘坐飞机直接从城市 1 到达城市 N&a…