【网络编程通关之路】 Tcp 基础回显服务器(Java实现)及保姆式知识原理详解 ! ! !

news2024/9/25 17:13:14

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在这里插入图片描述

引言

在这个数字化时代,信息的快速流通已成为我们日常生活的一部分。想象一下,当你发送一封电子邮件或浏览网页时,背后是一系列复杂的网络协议在默默工作,确保数据的准确传输。

今天,我们将聚焦于这些协议中的一个核心成员——传输控制协议(TCP)。TCP协议是互联网通信的基石,它通过确保数据的可靠传输,支撑着我们每天使用的无数网络服务。

目录

  1. Tcp回显服务器的普通实现

  2. Tcp 回显服务器的多线程实现

  3. Tcp 回显服务器的线程池实现

一. Tcp 回显服务器的普通实现

1. Tcp 的特点

在上一篇 实现Udp 的回显服务器的文章中 , 我们提及Tcp 和 Udp 分别有4个主要的特点

  • Tcp 是 可靠 传输, Udp是 不可靠 传输。
  • Tcp是面向 字节流, Udp是面向 数据报
  • Tcp 是 有连接 , Udp是 无连接
  • Tcp 是 全双工 , Udp也是 全双工

关于以上这些 特点 还有 回显服务器 的详解全部都收录到了 【网络编程通关之路】 Udp 基础回响服务器(Java实现)及你不知道知识原理详解 ! ! ! 这篇文章中 。

还没学习过或者忘记的小伙伴记得去看看哦。

2. Tcp使用的相关类

TcpUdp一样, 在进行网络通信的过程中,需要调用系统 Socket api , 但在 Java标准库 中已经封装好了相关的类, 通过这几个类, 在 JVM 中来调用系统原生的 Socket api操作网卡 , 进行网络通信。

关于Tcp 来实现回显

ServerSocket 类 :

在这里插入图片描述

  • 实例化ServerSocket 对象时, 只用于服务器一端 , 并且进行 端口号 连接 进程 的过程。

  • 用于建立 服务器客户端 连接,并且返回 Socket 对象。

    accept() 方法

鱼式疯言

从上面可以确定 Tcp的 有连接 的特点之一。

ServerSocket的构造方法 的连接是 端口号与进程的连接 , 相当于 “接好了电话线”

accept() 的连接是 服务器与客户端的连接 , 相当于 客户端那边给服务器 “打电话”, 而服务器这边就用 accept() 来接电话。完成连接。


Socket 类

在这里插入图片描述

  • 用于客户端与服务器连接:

    Socket 的构造方法, 在 实例化Socket 对象 时, 添加 IP地址端口号, 就意味着 建立了连接

  • 操作 Socket对象 来获取各种 IP地址 和 输入和输出流对象

    获取IP地址

    getInetAddress()

    获取输入字节流方法
    getInputStream()

    获取输出字节流方法

    getOutputStream()

鱼式疯言

  1. 由于我们 Tcp 特点 之一就是 面向字节流 , 并且是 全双工

所以我们既可以获取到 输入字节流对象 ,也可以获取到 输出字节流对象

  1. ServerSocket 类一般只适用于 服务器一端的端口号和进程的连接 , 而 Socket 一般只适用于 客户端一端服务器 的连接, 但是都适用于 服务器和客户端获取输入流与输出流 的操作。
  1. 同一台主机 上,同一个协议 , 一个 端口号 直接连接 一个进程

    但是在不同协议中, 一个端口号 可以连接 不同协议 下的进程。

  1. 无论是 ServerSocket 类 还是 Socket 类 , 都是属于 java.net 下的包的类。

回显服务器的普通实现代码展示

<1>. 服务器实现


package echoTCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;


public class MyTcpEchoServer {

    ServerSocket serverSocket = null;

    // 进行连接
    public MyTcpEchoServer(int port) {
        try {
            // 进行连接
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public  void start() {
        // 开始交互

        System.out.println("服务器开始运行...");
        while(true) {
        // 使用线程池





            Socket socket = null;

            try {
                socket = serverSocket.accept();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            // 进行接收请求并响应
            ProcessServerConnect(socket);



        }







    }

    private void ProcessServerConnect(Socket socket) {
            try(InputStream inputSTream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream()
            ) {


                while(true) {

                    System.out.printf("客户端上线 : [客户端ip = %s,
                    客户端端口号 = %d]\n"
                    ,socket.getInetAddress(),
                    socket.getPort());
                    
                    // 得到请求
                    Scanner scanner = new Scanner(inputSTream);
                    if(!scanner.hasNext()) {
                        break;
                    }

                    // 得到请求
                    String request = scanner.nextLine();

                    // 计算响应
                    // 执行业务
                   String response =  process(request);

                   // 返回响应
                   // 让客户端得到业务的执行结果
                   PrintWriter printWriter = new 
                   PrintWriter(outputStream);

                   // 开始返回
                   printWriter.println(response);
                   // 进行刷新
                    printWriter.flush();


//                    打印日志
                    System.out.printf("客户端下线 :  [ip = %s , 
                    port = %d], 请求 = %s , 响应 = %s\n",
                            socket.getInetAddress(),
                            socket.getPort(),request,response);


                }



            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                System.out.printf("任务执行结束: [%s,%d]\n",
                socket.getInetAddress(),
                socket.getPort());
                try {
//                    关闭 socket 流
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

    }

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


    public static void main(String[] args) {
        MyTcpEchoServer myTcpEchoServer = new MyTcpEchoServer(9090);
        myTcpEchoServer.start();
    }
}


在这里插入图片描述

服务器一端的实现的整体流程可分为以下几步:

  1. 创建 ServerSocket 对象 , 在构造方法中参数列表添加 端口号 , 建立端口号与进程的 连接
   // 进行连接
            serverSocket = new ServerSocket(port);
  1. 调用 accept 方法让服务器与客户端进行,并返回一个 Socket 对象。
   Socket socket = null;

        try {
            socket = serverSocket.accept();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
  1. 获取到输入流,利用 Scanner 包装输入流 得到请求
// 得到请求
Scanner scanner = new Scanner(inputSTream);
if(!scanner.hasNext()) {
    break;
}

// 得到请求
String request = scanner.nextLine();
  1. 计算响应 并把 输出流对象 包装到 printWriter 输出到客户端
// 计算响应
    // 执行业务
   String response =  process(request);

   // 返回响应
   // 让客户端得到业务的执行结果
   PrintWriter printWriter = new 
   PrintWriter(outputStream);

   // 开始返回
   printWriter.println(response);
// 进行刷新
    printWriter.flush();
  1. 打印日志,并关闭 Socket 对象
//                    打印日志
                 System.out.printf("客户端下线 :  [ip = %s , 
                 port = %d], 请求 = %s , 响应 = %s\n",
                         socket.getInetAddress(),
                         socket.getPort(),request,response);


             }



         } catch (IOException e) {
             throw new RuntimeException(e);
         } finally {
             System.out.printf("任务执行结束: [%s,%d]\n",
             socket.getInetAddress(),
             socket.getPort());
             try {
//                    关闭 socket 流
                 socket.close();
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
         }

鱼式疯言

补充细节

  1. 对于大部分 IO流 来说, 并不是 输入或输出一个/ 一段 就会加载到 硬盘 , 而是会存放到一个叫 缓冲区的地方, 当数据积攒到 一定的量 , 才会 加载过去

    所以我们为了每次只加载 一个 / 一段数据 , 可以调用 flush 这个方法 来将 缓冲区 的数据全部
    刷新出去

 // 进行刷新
      printWriter.flush();

  1. 小编在这里利用了 ScannerprintWriter 来包装输入和输出流。 但是小伙伴们也可以利用小编之前提及过的 IO流的操作方式 来进行哦, 效果是一样的 。

关于IO的流的操作文章, 可以多学习学习并且回去哦 💖 💖 💖 💖

IO流理论篇文章详解

IO流Java实践篇文章详解

  1. 对于上述 回显服务器 来说, 服务端一端 accept() 只有当服务器每次发来请求时,才会进行 连接, 否则进行 阻塞等待

<2>. 客户端实现

package echoTCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;


public class MyTcpEchoClient {
    Socket clientSocket = null;

    // 进行连接
    public MyTcpEchoClient(String ip , int port) {
        try {
            // 进行连接
            clientSocket = new Socket(ip, port);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public  void start() {
        // 开始交互


            System.out.println("客户端开始运行...");


                // 发送请求并接受响应
                ProcessServerConnect(clientSocket);


    }

    private void ProcessServerConnect(Socket socket) {
        try(InputStream inputSTream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()
        ) {

            while(true) {



                Scanner in = new Scanner(System.in);
                System.out.print("请输入你的需求-> ");


//                输入请求并发送
                String request = in.nextLine();

                PrintWriter printWriter = new 
                PrintWriter(outputStream);
                printWriter.println(request);
                // 进行刷新
                printWriter.flush();


                // 接收响应并输出
                Scanner scanner = new Scanner(inputSTream);
                if(!scanner.hasNext()) {
                    break;
                }

                String response = scanner.nextLine();

                System.out.println("response = "+ response);

            }



        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.printf("任务执行结束: 
            [%s,%d]\n",
            socket.getInetAddress(),
            socket.getPort());
            try {
//                    关闭 socket 流
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }


    public static void main(String[] args) {
        MyTcpEchoClient myTcpEchoClient = new 
        MyTcpEchoClient("127.0.0.1",9090);
        myTcpEchoClient.start();
    }
}

在这里插入图片描述

具体客户端一端的整体实现流程梳理

  1. 实例化Socket 对象, 并把 IP地址端口号 作为 Socket 构造方法的参数进行 客户端与服务端 的连接。
Socket clientSocket = null;

// 进行连接
public MyTcpEchoClient(String ip , int port) {
    try {
        // 进行连接
        clientSocket = new Socket(ip, port);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
  1. 输入请求 并发送给 客户端
                Scanner in = new Scanner(System.in);
                System.out.print("请输入你的需求-> ");


//                输入请求并发送
                String request = in.nextLine();

                PrintWriter printWriter = new 
                PrintWriter(outputStream);
                printWriter.println(request);
                // 进行刷新
                printWriter.flush();
  1. 接收服务器返回的 响应并输出
 // 接收响应并输出
    Scanner scanner = new Scanner(inputSTream);
    if(!scanner.hasNext()) {
        break;
    }

    String response = scanner.nextLine();

    System.out.println("response = "+ response);
  1. 宣布服务器执行结束, 并 关闭Socket对象
 finally {
            System.out.printf("任务执行结束: 
            [%s,%d]\n",
            socket.getInetAddress(),
            socket.getPort());
            try {
//                    关闭 socket 流
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

鱼式疯言

补充细节

  1. 对应上述代码中的 hasNext() 方法来说, 出现了 换行 才会 break 结束 出去, 而当 服务器/ 客户端 没有 发来数据时, 是会进入 阻塞等待 的, 不会break 直接跳出。
   if(!scanner.hasNext()) {
                break;
            }

二. Tcp 回显服务器的多线程实现

1. 代码展示

服务器源码

package echoTCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;


public class MyTcpEchoServer {

    ServerSocket serverSocket = null;

    // 进行连接
    public MyTcpEchoServer(int port) {
        try {
            // 进行连接
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public  void start() {
        // 开始交互

        System.out.println("服务器开始运行...");



//        使用多线程

        while(true) {
            Thread t = new Thread(()->{

                Socket socket = null;
                try {
                    socket = serverSocket.accept();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                // 进行接收请求并响应
                ProcessServerConnect(socket);


            });
            t.start();
        }




    }

    private void ProcessServerConnect(Socket socket) {
            try(InputStream inputSTream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream()
            ) {


                while(true) {

                    System.out.printf("客户端上线 : [客户端ip = %s,客户端端口号 = %d]\n",socket.getInetAddress(),socket.getPort());
                    // 得到请求
                    Scanner scanner = new Scanner(inputSTream);
                    if(!scanner.hasNext()) {
                        break;
                    }

                    // 得到请求
                    String request = scanner.nextLine();

                    // 计算响应
                    // 执行业务
                   String response =  process(request);

                   // 返回响应
                   // 让客户端得到业务的执行结果
                   PrintWriter printWriter = new PrintWriter(outputStream);

                   // 开始返回
                   printWriter.println(response);
                   // 进行刷新
                    printWriter.flush();


//                    打印日志
                    System.out.printf("客户端下线 :  [ip = %s , port = %d], 请求 = %s , 响应 = %s\n",
                            socket.getInetAddress(),socket.getPort(),request,response);


                }



            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());
                try {
//                    关闭 socket 流
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

    }

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


    public static void main(String[] args) {
        MyTcpEchoServer myTcpEchoServer = new MyTcpEchoServer(9090);
        myTcpEchoServer.start();
    }
}

客户端源码

package echoTCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;


public class MyTcpEchoClient {
    Socket clientSocket = null;

    // 进行连接
    public MyTcpEchoClient(String ip , int port) {
        try {
            // 进行连接
            clientSocket = new Socket(ip, port);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public  void start() {
        // 开始交互
            System.out.println("客户端开始运行...");


                // 发送请求并接受响应
                ProcessServerConnect(clientSocket);


    }

    private void ProcessServerConnect(Socket socket) {
        try(InputStream inputSTream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()
        ) {

            while(true) {



                Scanner in = new Scanner(System.in);
                System.out.print("请输入你的需求-> ");


//                输入请求并发送
                String request = in.nextLine();

                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                // 进行刷新
                printWriter.flush();


                // 接收响应并输出
                Scanner scanner = new Scanner(inputSTream);
                if(!scanner.hasNext()) {
                    break;
                }

                String response = scanner.nextLine();

                System.out.println("response = "+ response);



            }



        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());
            try {
//                    关闭 socket 流
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }


    public static void main(String[] args) {
        MyTcpEchoClient myTcpEchoClient = new MyTcpEchoClient("127.0.0.1",9090);
        myTcpEchoClient.start();
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 原理剖析

对于多线程的回显服务器的实现, 最主要是解决 多个 客户端同时给 一个 服务器 发送请求 的问题。

对于服务器来说 外边套着一个循环 , 里面又加了 一层循环 , 这样的话就会导致 两层循环 的加入

第一个客户端进入内循环 时, 它的任务还 没结束, 第二个客户端就向服务器 发送请求 , 这时由于内部的还 一直循环, 服务器就无法进入内循环 , 只能让第二个客户端一直停留在 缓冲区

这时我们就引入 多线程 的方式, 将每一个服务器都 分布同时 执行循环, 这样就能保证不会让 多个 服务器一直阻塞到 缓冲区

关于代码的实现实现流程, 只是在普通回显服务器的基础上加了 一行多线程 的代码。 其他都是一样的, 小编在这里就 不赘述了

三. Tcp 回显服务器的线程池实现

1. 代码展示

服务器一端

package echoTCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;


public class MyTcpEchoServer {

    ServerSocket serverSocket = null;

    // 进行连接
    public MyTcpEchoServer(int port) {
        try {
            // 进行连接
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public  void start() {
        // 开始交互

        System.out.println("服务器开始运行...");
        while(true) {
        // 使用线程池
        Executor executor = Executors.newCachedThreadPool();

        executor.execute(() -> {


            Socket socket = null;

            try {
                socket = serverSocket.accept();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            // 进行接收请求并响应
            ProcessServerConnect(socket);


        });
        }









    }

    private void ProcessServerConnect(Socket socket) {
            try(InputStream inputSTream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream()
            ) {


                while(true) {

                    System.out.printf("客户端上线 : [客户端ip = %s,客户端端口号 = %d]\n",socket.getInetAddress(),socket.getPort());
                    // 得到请求
                    Scanner scanner = new Scanner(inputSTream);
                    if(!scanner.hasNext()) {
                        break;
                    }

                    // 得到请求
                    String request = scanner.nextLine();

                    // 计算响应
                    // 执行业务
                   String response =  process(request);

                   // 返回响应
                   // 让客户端得到业务的执行结果
                   PrintWriter printWriter = new PrintWriter(outputStream);

                   // 开始返回
                   printWriter.println(response);
                   // 进行刷新
                    printWriter.flush();


//                    打印日志
                    System.out.printf("客户端下线 :  [ip = %s , port = %d], 请求 = %s , 响应 = %s\n",
                            socket.getInetAddress(),socket.getPort(),request,response);


                }



            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());
                try {
//                    关闭 socket 流
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

    }

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


    public static void main(String[] args) {
        MyTcpEchoServer myTcpEchoServer = new MyTcpEchoServer(9090);
        myTcpEchoServer.start();
    }
}

在这里插入图片描述
客户端一端

package echoTCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;


public class MyTcpEchoClient {
    Socket clientSocket = null;

    // 进行连接
    public MyTcpEchoClient(String ip , int port) {
        try {
            // 进行连接
            clientSocket = new Socket(ip, port);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public  void start() {
        // 开始交互
            System.out.println("客户端开始运行...");


                // 发送请求并接受响应
                ProcessServerConnect(clientSocket);


    }

    private void ProcessServerConnect(Socket socket) {
        try(InputStream inputSTream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()
        ) {

            while(true) {



                Scanner in = new Scanner(System.in);
                System.out.print("请输入你的需求-> ");


//                输入请求并发送
                String request = in.nextLine();

                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                // 进行刷新
                printWriter.flush();


                // 接收响应并输出
                Scanner scanner = new Scanner(inputSTream);
                if(!scanner.hasNext()) {
                    break;
                }

                String response = scanner.nextLine();

                System.out.println("response = "+ response);



            }



        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());
            try {
//                    关闭 socket 流
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }


    public static void main(String[] args) {
        MyTcpEchoClient myTcpEchoClient = new MyTcpEchoClient("127.0.0.1",9090);
        myTcpEchoClient.start();
    }
}

在这里插入图片描述

在这里插入图片描述

代码说明

关于线程池的代码实现: 主要还是在原来 普通 回显服务器的基础上, 加上了线程池的 newCachedThreadPool 对象 。

这个线程池对象在 任务繁忙 时, 最多可以创建出 Integer.MAX_VALUES非核心线程

具体详情小伙伴们可以参考多线程的文章, 有重点讲解哦

多线程实践篇详解

非常适合 服务器开发使用

  // 使用线程池
        Executor executor = Executors.newCachedThreadPool();

        executor.execute(() -> {


            Socket socket = null;

            try {
                socket = serverSocket.accept();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            // 进行接收请求并响应
            ProcessServerConnect(socket);


        });

鱼式疯言

如果是大量的客户端, 我们可能会用到上面的 线程池 来使用。

如果是海量的客户端使用, 就会使用 IO多路复用 (了解即可)。

总结

  1. Tcp回显服务器的普通实现: 从Tcp 的四大特点: 有连接, 面向字节流, 可靠传输, 全双工 的四个特点展开介绍 Tcp 的两个主要网络通信的类: ServerSocketSocket 两个类 ,并在代码中充分的使用并结合理解流程。

  2. Tcp 回显服务器的 多线程实现 : 利用多线程解决了一个服务器只能解决一个客户端的问题。

  3. Tcp 回显服务器的线程池实现: 从另外一个线程池的角度更解决大量客户端的问题。

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述

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

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

相关文章

QtCreator错误:Qt没有被正确安装,请运行make install(适用Qt4、Qt5、Qt6)

一、问题环境 &#xff08;1&#xff09;Windows 10企业版&#xff0c;64位 &#xff08;2&#xff09;Visual Studio 2019 &#xff08;3&#xff09;Qt5.12.12 x64版本&#xff08;自己编译&#xff09; &#xff08;4&#xff09;Qt Creator 12.0.1 二、问题描述&#…

CM工作室发展史 上

&#xff0c;注&#xff1a;本文章未使用"无标题技术" 目录 &#xff08;超长文章&#xff01;&#xff09; 新手时期 初来乍到 第一篇文章 第一个专栏——沙雕程序 学习"块引用" 第一次修改用户名 学习"代码" "头文件风波"时期 头…

什么是大模型的位置编码Position Encoding?

1. 什么是位置编码 位置编码&#xff08;Positional Encoding&#xff09;是一种在处理序列数据时&#xff0c;用于向模型提供序列中每个元素位置信息的技术。 在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;尤其是在使用Transformer模型时&#xff0c;位置编码尤…

科讯档案管理系统存在SQL注入漏洞(0day)

漏洞描述 安徽科迅教育装备20年来来始终坚持智慧校园集成方案产品的开发和部署应用&#xff0c;我们有完善的智慧校园和数字校园建设方案&#xff0c;根据不同的学校不同的实际情况量身定做系统集成方案。产品主要是为了实现校园的智慧网络、智慧OA、智慧教学、智慧学习、数字医…

【系统架构设计师-2018年】综合知识-答案及详解

文章目录 【第1题】【第2~3题】【第4题】【第5~6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16~17题】【第18~21题】【第22题】【第23题】【第24题】【第25题】【第26题】【第27~28题】【第29~30题】【第31题】【第32~3…

在 Debian 上安装 IntelliJ IDEA 笔记

在 Debian&#x1f4a9; 上安装 IntelliJ IDEA &#x1f4a1; 笔记 下载安装 JDK17安装 IntelliJ IDEA Community添加桌面启动项&#xff08;快捷方式&#xff09; 参考资料 下载 两个包已经下好了&#xff0c;一个JDK17&#xff0c;一个IntelliJ IDEA Community 使用 wget ur…

UE4 BuildCookRun中的Archive的含义

在UE4中&#xff0c;Archive、Cook、Stage、Package、Build的次序是怎么样的&#xff1f; 整体打包过程如下: Build -> Cook-> Stage -> Package -> Archive。其中&#xff0c;Archive 的含义是从Staged目录中拷贝文件到一个额外的目录即Archive目录。被称为“归档…

【2024-2025源码+文档+调试讲解】微信小程序的民宿预订系统springboot

摘要 随着网络科技的不断发展以及人们经济水平的逐步提高&#xff0c;网络技术如今已成为人们生活中不可缺少的一部分&#xff0c;而微信小程序是通过计算机技术&#xff0c;针对用户需求开发与设计&#xff0c;该技术尤其在各行业领域发挥了巨大的作用&#xff0c;有效地促进…

银河麒麟服务器中检查板卡速度和带宽是否降低

银河麒麟服务器中检查板卡速度和带宽是否降低 1. 查找板卡BUS ID2. 检查速度和带宽信息3. 解读结果结论 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在银河麒麟高级服务器操作系统中&#xff0c;快速检查板卡&#xff08;如网卡、显卡等…

CSS“叠叠乐”——WEB开发系列16

在现代前端开发中&#xff0c;CSS 是控制网页外观和布局的核心工具。随着项目的复杂化和样式规则的增加&#xff0c;CSS 层叠&#xff08;cascade&#xff09;变得更加重要。为了更好地管理和控制样式规则的应用&#xff0c;CSS 引入了层叠层&#xff08;cascade layers&#x…

C# 获取文件、文件夹和驱动器的信息详解与示例

文章目录 二、获取文件夹信息三、获取驱动器信息四、示例&#xff1a;文件、文件夹和驱动器信息工具五、异常处理六、总结 在C#中&#xff0c;文件、文件夹和驱动器是文件系统操作的基本元素。了解如何获取这些元素的信息对于开发文件处理和管理工具至关重要。本文将详细介绍如…

JAVA基础:文件字符流

目录 前言 文件字符流的创建 文件字符流的使用 前言 上一篇我们知道了如果在使用输入流读取数据时&#xff0c;数据中含有中文就会出现乱码的情况&#xff0c;这时就要使用字节字符转换流这个过程流来处理一下&#xff0c;针对这种情况我们可以直接使用文件字符流来读取数据…

计算机毕业设计hadoop++hive微博舆情预测 微博舆情分析 微博推荐系统 微博预警系统 微博数据分析可视化大屏 微博情感分析 微博爬虫 知识图谱

1.selenium爬取微博热搜、文章、评论数据存入mysql数据库&#xff0c;对评论lstm情感分析模型建模分析; 2.使用mapreduce对mysql中微博数据清洗&#xff0c;转为.csv文件上传hdfs文件系统&#xff1b; 3.使用hive建库建表,导入.csv数据集&#xff1b; 4.一半指标hive_sql进行离…

3_1_PID控制原理

自从计算机进入控制领域以来&#xff0c;用数字计算机代替模拟计算机调节器组成计算机控制系统&#xff0c;不仅可以用软件实现PID控制算法&#xff0c;而且可以利用计算机的逻辑功能&#xff0c;使PID控制更加灵活。数字PID控制在生产过程中是一种最普遍采用的控制方法&#x…

AI-Talk开发板外设测试

一、说明 需要先测试各外设的功能正常&#xff0c;再开发正式应用。SDK提供了两个测试工程&#xff0c;测试工程A和测试工程B。 二、测试工程 1、多模态开发板硬件检测工程A 检测的模块包括&#xff1a; - 摄像头 - 显示屏 - 触摸屏 - USB口&#xff08;csk_usb&#xff09;…

张宇36讲+1000题重点强化!保100冲120速刷攻略

如果你选择考研时全程跟随张宇的课程&#xff0c;基础阶段使用《张宇30讲》&#xff0c;强化阶段跟着《张宇36讲》&#xff0c;并且还要完成《张宇1000题》&#xff0c;那么你的任务量将非常大。尤其是今年&#xff0c;张宇老师的课程体系发生了重大调整&#xff1a; 张宇老师…

【字符串连接】输入两个字符串,将其进行连接然后输出

输入两个字符串&#xff0c;将其进行连接然后输出 使用C语言代码实现&#xff0c;具体代码&#xff1a; #include<stdio.h>int main(){char str1[100],str2[100];int i0,j0;printf("请输入第一个字符串:");scanf("%s",&str1);printf("请输…

SSRF漏洞与redis未授权访问的共同利用

1.利用靶场Pikachu来认识SSRF漏洞 1.什么是SSRF SSRF漏洞允许攻击者通过向服务器发起请求来伪造请求。这种漏洞的核心在于攻击者能够控制服务器向任意目标地址发起请求&#xff0c;而这些请求通常是攻击者无法直接从客户端发起的。 简单来说&#xff0c;假设你的网站有一个功能…

代谢组数据分析(十九):随机森林构建代谢组预后模型

介绍 建立胃癌(GC)预后模型时,从队列3中的181名患者中,使用右删失结果数据进行了随机分层抽样,分为训练数据集(n = 121)和测试数据集(n = 60)。训练了一个包含1000棵树的随机生存森林(RSF)模型,根据它们基于排列的特征重要性来选择突出的特征。通过再次训练随机生…

探索c++中的类型转化

文章目录 相关引入c中的转化机制const_castreinterpret_caststatic_castdynamic_cast 其他 相关引入 C语言中的类型转换: 有相关性的类型之间才能转换: 非相关性不能转换: c中的转化机制 const_cast 去掉常量属性 指针相同, 值不相同, 本质是编译器对这个常属性的a做了…