10.JAVAEE之网络编程

news2024/11/19 17:40:46

1.网络编程

  • 通过网络,让两个主机之间能够进行通信 =>基于这样的通信来完成一定的功能
  • 进行网络编程的时候,需要操作系统给咱们提供一组 AP1, 通过这些 API才能完成编程(API 可以认为是 应用层 和 传输层 之间交互的路径)(API:Socket API相当于一个插座:通过这一套 Socket AP| 可以完成不同主机之间,不同系统之间的网络通信)
  • 传输层,提供的网络协议,主要是两个:TCP UDP
  • 这俩协议的特性(工作原理) 差异很大.导致,使用这两种协议进行网络编程,也存在一定差别系统就分别提供了两套 API
  • TCP 和 UDP 的区别.(后面网络原理章节, 学习的重点)

       1.TCP 是有连接的, UDP 是无连接的

       2.TCP 是可靠传输的,UDP 是不可靠传输的

       3.TCP 是面向字节流的,UDP 是面向数据报

       4.TCP 和 UDP 都是全双工的

 1.TCP 是有连接的, UDP 是无连接的
(连接 是 抽象 的概念)
计算机中,这种 抽象 的连接是很常见的,此处的连接本质上就是建立连接的双方,各自保存对方的信息两台计算机建立连接,就是双方彼此保存了对方的关键信息~~
TCP 要想通信, 就需要先建立连接 (刚才说的, 保存对方信息),做完之后,才能后续通信(如果 A 想和 B 建立连接, 但是 B 拒绝了! 通信就无法完成!!!)

UDP 想要通信,就直接发送数据即可~~不需要征得对方的同意,UDP 自身也不会保存对方的信息(UDP 不知道,但是写程序的人得知道.UDP 自己不保存,但是你调用 UDP 的 socket api的时候要把对方的位置啥的给传过去)

2.TCP 是可靠传输的,UDP 是不可靠传输的
网络上进行通信, A ->B 发送一个消息,这个消息是不可能做到 100% 送达的!! 

可靠传输,退而求其次.
A ->B 发消息,消息是不是到达 B 这一方,A 自己能感知到.(A 心里有数)进一步的,就可以在发送失败的时候采取一定的措施(尝试重传之类的)

TCP 就内置了可靠传输机制;UDP 就没有内置可靠传输

【tips】可靠传输,听起来挺美好的呀, 为啥不让 UDP 也搞个可靠传输呢??

想要可靠传输,你就是要付出代价的(需要去交换)
可靠传输要付出什么代价?
1)机制更复杂
2)传输效率会降低

3.TCP 是面向字节流的,UDP 是面向数据报
此处说的 字节流 和 文件 操作这里的 字节流 是一个意思!!!
TCP 也是和文件操作一样,以字节为单位来进行传输.
UDP 则是按照数据报为单位,来进行传输的
UDP 数据报是有严格的格式的 

网络通信数据的基本单位,涉及到多种说法~~
1.数据报(Datagram)
2.数据包(Packet)

3.数据帧(Frame)
4.数据段 (Segment) 

4. TCP 和 UDP 都是全双工的
一个信道,允许双向通信, 就是全双工
一个信道,只能单向通信,就是半双工
代码中使用一个 Socket 对象, 就可以发送数据也能接受数据~~ 

2.UDP 的 socket api 如何使用

Datagramsocket 

Datagrampacket 

【回显服务器:(echo server)】

写一个简单的 UDP 的客户端/服务器 通信的程序.
这个程序没有啥业务逻辑,只是单纯的调用 socket api.
让客户端给服务器发送一个请求,请求就是一个从控制台输入的字符串.
服务器收到字符串之后,也就会把这个字符串原封不动的返回给客户端,客户端再显示出来. 

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();
    }
}
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();
    }
}

【客户端】

  • 对于服务器来说,也就需要把端口号给明确下来了~~
  • 客户端的端口号是不需要确定的.交给系统进行分配即可,
  • 如果你手动指定确定的端口,就可能和别人的程序的端口号冲突
  • 【tips】服务器这边手动指定端口,就不会出现冲突嘛??
    为啥客户端在意这个冲突,而服务器不在意呢??

    服务器是在程序猿手里的,一个服务器上都有哪些程序, 都使用哪些端口,程序猿都是可控的!!程序猿写代码的时候,就可以指定一个空闲的端口,给当前的服务器使用即可
    但是客户端就不可控,客户端是在用户的电脑上;一方面,用户千千万~~ 每个用户电脑上装的程序都不一样,占用的端口也不一样;交给系统分配比较稳妥.系统能保证肯定分配一个空闲的端口

服务器一旦启动,就会立即执行到这里的 receive 方法此时,客户端的请求可能还没来呢~~
这种情况也没关系.receive 就会直接阻塞, 就会一直阻塞到真正客户端把请求发过来为止,(类似于阻塞队列)

【question】

//根据请求计算响应(核心步骤)

这个步骤是一个服务器程序,最核心的步骤!!!
咱们当前是 echo server 不涉及到这些流程,也不必考虑响应怎么计算,只要请求过来,就把请求当做响应

【question】

【question】上述写的代码中,为啥没写 close??
socket 也是文件,不关闭不就出问题了,不就文件资源泄露了么,为啥这里咱们可以不写 close?为啥不写 close 也不会出现文件资源泄露??

private DatagramSocket socket = null;
这个 socket 在整个程序运行过程中都是需要使用的(不能提前关闭)当 socket 不需要使用的时候, 意味着程序就要结束了

进程结束,此时随之文件描述符表就会销毁了(PCB 都销毁了).谈何泄露??
随着销毁的过程,被系统自动回收了~~

啥时候才会出现泄露?代码中频繁的打开文件,但是不关闭在一个进程的运行过程中,不断积累打开的文件,逐渐消耗掉文件描述符表里的内容最终就消耗殆尽了
但是如果进程的生命周期很短,打开一下没多久就关闭了.谈不上泄露
文件资源泄露这样的问题,在服务器这边是比较 严重的, 在客户端这边一般来说影响不大.

 【服务器】

【交互】

1.服务器先启动.服务器启动之后,就会进入循环,执行到 receive 这里并阻塞 (此时还没有客户端过来呢)
2.客户端开始启动,也会先进入 while 循环,执行 scanner.next.并且也在这里阻塞当用户在控制台输入字符串之后,next 就会返回,从而构造请求数据并发送出来~~

3.客户端发送出数据之后,
服务器: 就会从 receive 中返回,进一步的执行解析请求为字符串,执行 process 操作,执行 send 操作
客户端: 继续往下执行,执行到 receive,等待服务器的响应

4.客户端收到从服务器返回的数据之后,就会从 receive 中返回执行这里的打印操作,也就把响应给显示出来了
5.服务器这边完成一次循环之后, 又执行到 receive 这里,客户端这边完成一次循环之后,又执行到 scanner.next 这里双双进入阻塞

 【翻译服务器】

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", "小猪");
    }

    // 重写 process 方法, 在重写的方法中完成翻译的过程.
    // 翻译本质上就是 "查表"
    @Override
    public String process(String request) {
        return dict.getOrDefault(request, "该词在词典中不存在!");
    }

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

上述重写 process 方法,就可以在子类中组织你想要的"业务逻辑",(你要写代码解决一些实际的问题)

3.TCP 的 socket api 如何使用 

TCP 的 socket api 和 UDP 的 socket api 差异又很大~,

但是和前面讲的 文件操作,有密切联系的

两个关键的类

1.ServerSocket(给服务器使用的类,使用这个类来绑定端口号)

2.Socket(既会给服务器用,又会给客户端用)

这俩类都是用来表示 socket 文件的,(抽象了网卡这样的硬件设备)

TCP 是字节流的.传输的基本单位,是 byte

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

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        // 需要在创建 Socket 的同时, 和服务器 "建立连接", 此时就得告诉 Socket 服务器在哪里~~
        // 具体建立连接的细节, 不需要咱们代码手动干预. 是内核自动负责的.
        // 当我们 new 这个对象的时候, 操作系统内核, 就开始进行 三次握手 具体细节, 完成建立连接的过程了.
        socket = new Socket(serverIp, serverPort);
    }

    public void start() {
        // tcp 的客户端行为和 udp 的客户端差不多.
        // 都是:
        // 3. 从服务器读取响应.
        // 4. 把响应显示到界面上.
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            PrintWriter writer = new PrintWriter(outputStream);
            Scanner scannerNetwork = new Scanner(inputStream);
            while (true) {
                // 1. 从控制台读取用户输入的内容
                System.out.print("-> ");
                String request = scanner.next();
                // 2. 把字符串作为请求, 发送给服务器
                //    这里使用 println, 是为了让请求后面带上换行.
                //    也就是和服务器读取请求, scanner.next 呼应
                writer.println(request);
                writer.flush();
                // 3. 读取服务器返回的响应.
                String response = scannerNetwork.next();
                // 4. 在界面上显示内容了.
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}
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.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    private ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService service = Executors.newCachedThreadPool();
        while (true) {
            // 通过 accept 方法, 把内核中已经建立好的连接拿到应用程序中.
            // 建立连接的细节流程都是内核自动完成的. 应用程序只需要 "捡现成" 的.
            Socket clientSocket = serverSocket.accept();
            // 此处不应该直接调用 processConnection, 会导致服务器不能处理多个客户端.
            // 创建新的线程来调用更合理的做法.
            // 这种做法可行, 不够好
//            Thread t = new Thread(() -> {
//                processConnection(clientSocket);
//            });
//            t.start();

            // 更好一点的办法, 是使用线程池.
            service.submit(new Runnable() {
                @Override
                public void run() {
                    processConnection(clientSocket);
                }
            });
        }
    }

    // 通过这个方法, 来处理当前的连接.
    public void processConnection(Socket clientSocket) {
        // 进入方法, 先打印一个日志, 表示当前有客户端连上了.
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
        // 接下来进行数据的交互.
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            // 使用 try ( ) 方式, 避免后续用完了流对象, 忘记关闭.
            // 由于客户端发来的数据, 可能是 "多条数据", 针对多条数据, 就循环的处理.
            while (true) {
                Scanner scanner = new Scanner(inputStream);
                if (!scanner.hasNext()) {
                    // 连接断开了. 此时循环就应该结束
                    System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
                    break;
                }
                // 1. 读取请求并解析. 此处就以 next 来作为读取请求的方式. next 的规则是, 读到 "空白符" 就返回.
                String request = scanner.next();
                // 2. 根据请求, 计算响应.
                String response = process(request);
                // 3. 把响应写回到客户端.
                //    可以把 String 转成字节数组, 写入到 OutputStream
                //    也可以使用 PrintWriter 把 OutputStream 包裹一下, 来写入字符串.
                PrintWriter printWriter = new PrintWriter(outputStream);
                //    此处的 println 不是打印到控制台了, 而是写入到 outputStream 对应的流对象中, 也就是写入到 clientSocket 里面.
                //    自然这个数据也就通过网络发送出去了. (发给当前这个连接的另外一端)
                //    此处使用 println 带有 \n 也是为了后续 客户端这边 可以使用 scanner.next 来读取数据.
                printWriter.println(response);
                //    此处还要记得有个操作, 刷新缓冲区. 如果没有刷新操作, 可能数据仍然是在内存中, 没有被写入网卡.
                printWriter.flush();
                // 4. 打印一下这次请求交互过程的内容
                System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(),
                        request, response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 在这个地方, 进行 clientSocket 的关闭.
                // processConnection 就是在处理一个连接. 这个方法执行完毕, 这个连接也就处理完了.
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public String process(String request) {
        // 此处也是写的回显服务器. 响应和请求是一样的.
        return request;
    }

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

【服务器】

内核中有一个“队列”(可以视为阻塞队列)

如果有客户端,和服务器建立连接,这个时候服务器的应用程序是不需要做出任何操作(也没有任何感知的),内核直接就完成了连接建立的流程(三次握手).

完成流程之后,就会在内核的队列中(这个队列是每个 serverSocket 都有一个这样的队列)。

排队应用程序要想和这个客户端进行通信,就需要通过一个 accept 方法把内核队列里已经建立好的连接对象,拿到应用程序中。

【question】

前面写过的 DatagramSocket, ServerSocket 都没写 close, 但是我们说这个东西都没关系但是 clientSocket 如果不关闭,就会真的泄露了!!!
DatagramSocket 和 ServerSocket,都是在程序中,只有这么一个对象.申明周期, 都是贯穿整个程序的.

而ClientSocket 则是在循环中,每次有一个新的客户端来建立连接,都会创建出新的clientSocket

每次执行这个,都会创建新的 clientSocket,并且这个 socket 最多使用到 该客户端退出(断开连接)
此时,如果有很多客户端都来建立连接~~此时,就意味着每个连接都会创建 clientSocket.当连接断开clientSocket 就失去作用了,但是如果没有手动 close此时这个 socket 对象就会占据着文件描述符表的位置

【客户端】

【question】出现一个bug

当前启动两个客户端,同时连接服务器.
其中一个客户端(先启动的客户端) 一切正常.
另一个客户端 (后启动的客户端)则没法和服务器进行任何交互,(服务器不会提示"建立连接”,也不会针对 请求 做出任何响应)

上述bug和代码结构密切相关

确实如刚才推理的现象一样,第一个客户端结束的时候,就从 processConnection 返回了就可以执行到第二次 accept 了,也就可以处理第二个客户端了~~
很明显,如果启动第三个客户端,第三个客户端也会僵硬住,又会需要第二个客户端结束才能活过来...

如何解决上述问题?让一个服务器可以同时接待多个客户端呢??

关键就是,在处理第一个客户端的请求的过程中,要让代码能够快速的第二次执行到 accept ~~~【多线程】

上述这里的关键,就是让这两个循环能够"并发"执行.
各自执行各自的,不会因为进入一个循环影响到另一个~~

【刚才出现这个问题的关键在于两重循环在一个线程里进入第二重循环的时候,无法继续执行第一个循环.
Udp 版本的服务器,当时是只有一个循环,不存在类似的问题~~(前面部署到云服务器的时候)】

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

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

相关文章

【Qt常用控件】—— QWidget 核心属性

目录 &#xff08;一&#xff09;控件概述 1.1 关于控件体系的发展 &#xff08;二&#xff09;QWidget 核心属性 2.1 核心属性概览 2.2 enabled 2.3 geometry 2.4 windowTitle 2.5 windowIcon 2.6 windowOpacity 2.7 cursor 2.8 font 2.9 toolTip 2.10 focus…

java的ArrayList LinkedList的操作

文章目录 ArrayList1. ArrayList集合的特点2. 操作 LinkedList1. LinkedList集合的特点2. 操作 参考链接 ArrayList 1. ArrayList集合的特点 2. 操作 add(Object element) 向列表的尾部添加指定的元素。size() 返回列表中的元素个数。get(int index) 返回列表中指定位置的元素…

Git ignore、exclude for TortoiseGit 小结

1.Ignore Type&#xff1a;忽略类型&#xff0c;也即忽略规则&#xff0c;如何去忽略文件? 1.1.Ignore item(s) only in containing folder(s)&#xff1a;仅忽略在包含在文件夹中项目。 仅忽略该文件夹下选定的patterns。the patterns其实就是文件类型&#xff0c;比如.txt后…

MATLAB循环语句

MATLAB 循环语句 在某些情况下&#xff0c;您需要多次执行一个代码块。通常&#xff0c;语句是按顺序执行的。首先执行函数中的第一条语句&#xff0c;然后执行第二条&#xff0c;依此类推。 编程语言提供了各种控制结构&#xff0c;允许更复杂的执行路径。 循环语句允许我们…

把 KubeBlocks 跑在 Kata 上,真的可行吗?

背景 容器的安全性一直是广受关注的话题。这个领域也产生了很多不错的开源项目。Kata就是其中之一。 Kata Containers&#xff08;简称 Kata&#xff09;是一种开源项目&#xff0c;它提供了一种安全而高性能的容器运行时环境。Kata Containers 利用虚拟化技术&#xff08;通常…

【深度学习实战(24)】如何实现“断点续训”?

一、什么是断点续训&#xff1a; 中断的地方&#xff0c;继续训练。与加载预训练权重有什么区别呢&#xff1f;区别在于优化器参数和学习率变了。 二、如何实现“断点续训” 我们需要使用checkpoint方法保存&#xff0c;模型权重&#xff0c;优化器权重&#xff0c;训练轮数…

TablePlus for Mac/Win:开启高效数据开发新纪元

在当今数字化时代&#xff0c;数据的重要性日益凸显。无论是企业还是个人&#xff0c;都需要一款强大而实用的本地原生数据开发软件来提升工作效率。而 TablePlus for Mac/Win 正是这样一款卓越的工具&#xff0c;它为用户带来了全新的体验&#xff0c;让数据开发变得更加轻松、…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(三)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 4 - 6节&#xff09; P5《04.快速入门》 本节来实现一个 HelloWorld 效果&#xff1a; 1、打开编辑器&#xff0c;选择新建项目&…

【matlab】reshape函数介绍及应用

【matlab】reshape函数介绍及应用 【先赞后看养成习惯】求点赞关注收藏&#x1f600; 在MATLAB中&#xff0c;reshape函数是一种非常重要的数组操作函数&#xff0c;它可以改变数组的形状而不改变其数据。本文将详细介绍reshape函数的使用方法和应用。 1. reshape函数的基本语…

Redisson分布式锁 --- 源码分析

1.获取一把锁 RLock lock redissonClient.getLock("订单lock"); 2.业务代码加锁 lock.lock(); 2.1 lock.tryAcquire Long ttl tryAcquire(leaseTime, unit, threadId); 2.2 lua脚本: tryLockInnerAsync方法 如果获取锁失败&#xff0c;返回的结果是这个key的剩…

ssm项目搭建,springboot项目搭建

一、springboot项目搭建 1.新建一个文件夹用idea打开 2.配置maven工作目录、jdk路径、编码方式 3.pom.xml依赖管理&#xff1a;不同的项目&#xff0c;只需要修改下面的三行就可以 <groupId>com.qcby</groupId> <artifactId>HXQ0419</artifactId> &l…

如何安装、升级英伟达显卡驱动

目录 方式一&#xff1a;GeForce Experience 方式二&#xff1a;英伟达官网手动下载驱动 在做深度学习的过程中&#xff0c;难免会使用到cudatoolkit&#xff0c;而cudatoolkit又需要跟英伟达显卡驱动适配。比如笔者使用的电脑目前安装的英伟达显卡驱动 Driver Version: 516.…

git的安装与配置教程--超详细版

一、git的安装 1. 官网下载git git官网地址&#xff1a;https://git-scm.com/download/win/ 选择需要的版本进行下载 2、下载完成之后&#xff0c;双击下载好的exe文件进行安装。 3、默认是C盘&#xff0c;推荐修改一下路径&#xff0c;然后点击下一步 4、Git配置&#xff…

Java虚拟机(jvm)常见问题总结

1.电脑怎样认识我们编写的Java代码 首先先了解电脑是二进制的系统&#xff0c;他只认识 01010101比如我们经常要编写 HelloWord.java 电脑是怎么认识运行的HelloWord.java是我们程序员编写的&#xff0c;我们人可以认识&#xff0c;但是电脑不认识 Java文件编译的过程 1. 程…

4.25日学习记录

[HZNUCTF 2023 preliminary]ppppop 对于php反序列化&#xff0c;在之前的学习中有过了解&#xff0c;但是对于序列化字符串的格式不是很了解&#xff0c;刚好接触这题&#xff0c;可以了解一下 序列化字符串的格式&#xff1a; 布尔型&#xff08;bool&#xff09;b&#xf…

bugfix: com.alibaba.druid.sql.parser.EOFParserException: EOF

前言 在日常的开发工作中&#xff0c;我们经常会遇到各种各样的问题&#xff0c;其中涉及数据库操作的接口联调尤其容易出现意想不到的状况。今天我就遇到了一个关于Druid SQL解析异常的问题&#xff0c;具体表现为com.alibaba.druid.sql.parser.EOFParserException: EOF。通过…

盲人使用公共设施:科技助力无障碍出行与智能识别

在我们的日常生活中&#xff0c;公共设施扮演着不可或缺的角色&#xff0c;它们为人们提供了便利的服务&#xff0c;构建起和谐、高效的社会环境。然而&#xff0c;对于视障人士而言&#xff0c;尽管公共设施设计之初便考虑到通用性和包容性&#xff0c;实际使用过程中仍难免遭…

云原生Kubernetes: K8S 1.29版本 部署Nexus

目录 一、实验 1.环境 2.搭建NFS 3. K8S 1.29版本 部署Nexus 二、问题 1.volumeMode有哪几种模式 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注masterK8S master节点1.29.0192.168.204.8 node1K8S node节点1.29.0192.168.204.9node2K…

【代码复现】Ultra-Fast-Lane-Detection-V2 代码复现。

GitHub源码&#xff1a;https://github.com/cfzd/Ultra-Fast-Lane-Detection-v2?tabreadme-ov-file 按照 install.md复现遇到的问题&#xff1a; 这行命令有问题&#xff0c;先跳过。改用如下命令&#xff1a; pip install torch1.8.0cu111 torchvision0.9.0cu111 torchaud…

猫头虎分享已解决Bug || TypeError: Cannot read property ‘map‘ of undefined**

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …