网络编程的学习初篇

news2024/11/15 9:47:03

previewfile_3005866398

网络原理初始

网络原理和网络编程[重要]
网络能够跨主机通信!
我们未来工作,很可能是成为后端开发工程师,写服务器,和客户端通信,肯定会涉及到网络.

网络初始

计算机网络的由来

~~ 计算机网络这是计科相关专业最核心的专业课!!!

计算机是咋来的??最初是用来计算弹道导弹的轨迹 => 为了打仗
计算机网络是咋来的?同理,也是打仗打出来的!!!
互联网之前,可以通过有线/无线,发电报,有电话.缺点非常明显,通信链路容易被打击.

二战之后 ~~ 美苏争霸,冷战
武器不停升级=>核武器, 杀伤力太大了 ~~ 使用核武器,妥妥的把你通信链路,连根拔起.
美国人开始研究,有没有办法,能够搞出一种通信手段,即使是核武器,也打击不了!!
古巴导弹危机
美国人开始在北约,部署核武器,能直接威胁到苏联本土
古巴离美国本土太近了,苏联人就准备在古巴,部署核武器,直接威胁到美国本土最后苏联放弃了,核战争没打起来.

上个世纪,80年代左右,网络还处在萌芽阶段.不过,有些学校/研究所,已经尝试把计算机进行相连,可以进行简单的网络通信了.
到了后来,这个时候,时代背景,冷战(局势是非常紧张的)

这个事情完了之后,大国就开始反思,
在这种核威慑下,如何才能保证足够的威慑力??
A和B相互威慑,意思就是A可以对B进行核打击.但是B在承受打击之后,仍然有能力进行反制(对A进行核打击)如果B的反击能够成立,此时意味着A和B之间谁都不敢轻举妄动.

A打击B要打击哪里?
1.政府核心机构 ~~ 重点目标,必然重点保护,想打掉没那么容易!!!
2.打击B的导弹发射井 ~~ 重点目标,必然重点保护 ~~ 想打掉没那么容易!!!
3.打击网络通信系统 => 假设A把B的网络系统打掉了,此时B想反制,肯定是政府核心机构,发起打击命令,由导弹发射井执行~~此时命令可能就传不过去了!!

因此,研究重点,就是研究出一种通信网络,不怕核打击!!!
在上述背景下,互联网,就应运而生了.

关键问题,万一真的受到核打击了,通信链路仍然正常,因此可以发出指令,进行核反击

image-20231017151656714

后来大家就发现了,互联网这个东西,民用更香!!!就衍生出了很多很多的公司和产品,构建成了咱们今天的丰富的互联网世界.
现在互联网已经渗透到生活中的方方面面了,国内的互联网兴起,得是从2000年左右开始算了.

网络编程

基于操作系统提供的socket api来进行网络数据的发送和接收,Java在JVM中又进行了封装.名字上还是叫做Socket,让内核中的传输层协议和咱们应用程序中应用层的协议进行相互通信.

传输层的主要协议: TCP ,UDP
UDP:无连接,不可靠传输,面向数据报,全双工
TCP:有连接,可靠传输,面向字节流,全双工
代码写的风格差别很大.

DatagramSocket: 代表着 socket 文件(操作系统操作网卡,也不是直接操作,而是把网卡抽象成了特殊的文件,称为 socket 文件).
对 UDP 来说,传输数据的基本单位,DatagramPacket指定一个字节数组,作为持有数据的缓冲区.
一次通信涉及到源IP,源端口,目的IP,目的端口,协议类型

死循环在服务器程序中没什么问题,生活中使用的大部分的程序的服务器都是7 * 24小时的.
当然,有的服务器比较牛,不是 7 * 24小时运行…典型代表: 12306 23:00->6:00进行维护

UDP版本的回显服务器

部分相关代码

package network;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fly(逐梦者)
 * Date: 2023-10-17
 * Time: 19:22
 */

// UDP 版本的回显服务器
public class UdpEchoServer {
    // 网络编程,本质上是要操作网卡
    // 但是网卡不方便直接操作,在操作系统内核中,使用了一种特殊的叫做 "socket" 这样的文件来抽象表示网卡
    // 因此进行网络通信,势必需要有一个 socket
    private DatagramSocket socket = null;

    // 对于服务器来说,创建 socket 对象的同时,要让他绑上一个具体的端口号
    // 服务器一定要关联上一个具体的端口
    // 服务器是网络传输中,被动的一方,如果是操作系统随机分配的端口,此时客户端就不知道这个端口是什么了,也就无法进行通信了.
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        // 服务器不是只给一个客户端提供服务,需要服务很多客服端
        while (true) {
            // 只要有客户端过来,就可以提供服务
            // 1. 读取客户端发送的请求
            //    receive方法的参数是一个输出型参数,
            //    需要先构造好个空白的 DatagramPacket 对象, 交给 receive 来进行填充.
            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. 把响应数据写回到客户端, send 的参数也是 DatagramPacket,需要把这个 Packet 对象构造好.
            //    此处构造的响应对象,不能是用空的字节数组构造了,而是要使用响应数据来构造.
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length
                    , requestPacket.getSocketAddress());
            socket.send(responsePacket);
        }
    }
    // 这个方法就表示"根据请求计算响应"
    private String process(String request) {
        return request;
    }
}

image-20231018195246690

代码的注解

image-20231018204629510

image-20231018225532796

服务器的工作流程.
1.读取请求并解析
2.根据请求计算响应
3.构造响应并写回给客户端

客户端这边的代码

image-20231018235452114

注: 端口号用来标识/区分一个进程.因此在同一个主机上,不允许一个端口同时被多个进程使用.
不过,一个进程可以绑定多个端口,进程只要创建多个 socket 对象,就可以分别关联不同的端口.
总结: socket 和 端口号是一对一的,进程和 socket 是一对多的.

对于服务器,端口必须是确定好的,对于客户端来说,端口可以是系统分配的.
虽然客户端可以做到指定端口号,但是不推荐!!! 因为客户端如果显示指定端口,可能就和客户端电脑上的其他程序的端口冲突了,这一冲突就可能导致程序无法正确通信了(运行就会抛出异常,提示绑定端口失败).

问题来了: 为什么服务器这里指定端口就不怕重复呢?
服务器是我们程序猿自己手里的机器,上面运行啥,都是可控的.我们可以安排哪个程序用哪个端口[可控的]
客户端的机器是在用户手里的,不同用户手里的机器,种类繁多,上面运行着哪些程序,也各有不同[不可控]

总结: 服务器的端口是要固定指定的,目的是为了方便客户端找到服务器程序.
客户端的端口是由系统自动分配的,如果手动指定,可能会和客户端其他程序的端口冲突.
服务器不怕冲突的原因,因为服务器上面的程序可控.客户端是运行在用户电脑上,环境更复杂,更不可控.

image-20231019145332507

image-20231020143755379

我们看到的IP地址: 127.0.0.1 => 32位的整数(给计算机看的).
点分十进制(给人看的),每个部分,范围是 0-255 一个字节.

DatagramSocket这个类的receive能阻塞,是因为操作系统原生提供的APl (recv)就是阻塞的函数.
这里的阻塞不是Java 实现的,而是系统内核里实现的.
系统里对于IO操作本身就有这样阻塞等待的机制.
哪个线程如果进行IO操作,在IO完成之前,就会自动把对应的线程放到阻塞队列中,暂时不参与调度.

对于客户端服务器程序来说一个服务器要给很多客户端提供服务的,我们也就需要构造出多个客户端来进行测试.
由于 IDEA 默认只能启动一个客户端所以需要稍微调整一下,让idea 能启动多个客户端.

image-20231020153722524

修改后的运行结果展示

image-20231020154126177

注: 当前的客户端和服务器程序,都是在博主自己的笔记本上跑的,而实际上,网络存在的意义,是跨主机通信的.
但是如果我把客户端的代码发给别人,别人是连不上我笔记本上的服务器程序的.
但是有解决办法: 让其他人连上“云服务器”这样的特殊电脑,“云服务器”有外网 IP,任何一个连上网络的设备都能访问(博主的笔记本电脑是没有外网IP,只能在局域网内部访问,所以别人是连不上我笔记本上的服务器程序的)

把程序部署到云服务器(了解即可)
1.把java程序打包.
image-20231020220421283

image-20231020220955618

image-20231020221628095

上述操作的结果

image-20231020222230078

2.对云服务器(Linux系统)相关操作

image-20231020230510912

将IP地址更改为云服务器的IP

image-20231020230417535

image-20231020230528463

博主的笔记本电脑和云服务器(另一个主机)跨越网络进行通讯了.
注: 可以把代码发给其他人,这样你们观看云服务器上的你们发送的信息进行交流了.
image-20231020231559564

相关的完整代码

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fly(逐梦者)
 * Date: 2023-10-17
 * Time: 19:23
 */


// UDP 版本的 回显客户端
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp = null;
    private int serverPort = 0;

    // 一次通信,需要有两个ip,两个端口
    // 此时客户端的 ip 是 127.0.0.1 已知的
    // 客户端的 port 是系统自动分配的
    // 服务器 ip 和 端口 也需要告诉客户端,才能顺利把消息发到服务器
    public UdpEchoClient(String serverIp, int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1.从控制台读取数据
            System.out.print("> ");
            String request = scanner.next();
            if (request.equals("exit")) {
                System.out.println("goodbye");
                break;
            }
            // 2. 构造成 UDP 请求
            //    构造这个 Packet 的时候,需要把 serverIP 和 port 都传入过来,但是此处 IP 地址需要填写的是一个 32 位的整数形式.
            //    上述的 IP 地址是一个字符串,需要使用 InetAddress.getByName 来进行一个转换.
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(serverIp), serverPort);
            socket.send(requestPacket);
            // 3.读取服务器的 UDP 响应, 并解析
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0,responsePacket.getLength(),"utf8");
            // 4. 把解析好的结果显示出来
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client=new UdpEchoClient("127.0.0.1",9090);
        client.start();
    }
}
UdpEchoServer.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fly(逐梦者)
 * Date: 2023-10-17
 * Time: 19:22
 */

// UDP 版本的回显服务器
public class UdpEchoServer {
    // 网络编程,本质上是要操作网卡
    // 但是网卡不方便直接操作,在操作系统内核中,使用了一种特殊的叫做 "socket" 这样的文件来抽象表示网卡
    // 因此进行网络通信,势必需要有一个 socket
    private DatagramSocket socket = null;

    // 对于服务器来说,创建 socket 对象的同时,要让他绑上一个具体的端口号
    // 服务器一定要关联上一个具体的端口
    // 服务器是网络传输中,被动的一方,如果是操作系统随机分配的端口,此时客户端就不知道这个端口是什么了,也就无法进行通信了.
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        // 服务器不是只给一个客户端提供服务,需要服务很多客服端
        while (true) {
            // 只要有客户端过来,就可以提供服务
            // 1. 读取客户端发送的请求
            //    receive方法的参数是一个输出型参数,
            //    需要先构造好个空白的 DatagramPacket 对象, 交给 receive 来进行填充.
            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. 把响应数据写回到客户端, send 的参数也是 DatagramPacket,需要把这个 Packet 对象构造好.
            //    此处构造的响应对象,不能是用空的字节数组构造了,而是要使用响应数据来构造.
            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()/*获取到packet里面的ip*/,
                    requestPacket.getPort()/*获取到里面的端口*/,request,response);
        }
    }
    // 这个方法就表示"根据请求计算响应"
    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        // 端口号的指定,可以随便指定
        // 1024 -> 65535 这个范围里随便挑个数字就行了
        UdpEchoServer server=new UdpEchoServer(9090);
        server.start();
    }
}

实现一个简单的翻译程序

回显服务器,缺少业务逻辑
就在上述代码的基础上稍作调整,就可以实现一个“查词典”的服务器(英文单词,翻译成中文解释).
注: 代码主要是复用了之前 EchoServer 的代码,然后重写 process 就行了.

不同的服务器,对应的服务器是不同的,因此,处理的流程就是不同的,对于一些复杂的服务器, process 里面可能要运行几万行,几十万行……

UdpDictServer.java

import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fly(逐梦者)
 * Date: 2023-10-21
 * Time: 0:01
 */

// 对于 DictServer 来说, 和 EchoServer 相比,大部分的东西都是一样的.
// 主要是 "根据请求计算响应" 这个步骤不太一样.
public class UdpDictServer extends UdpEchoServer {

    private Map<String, String> dict = new HashMap<>();

    public UdpDictServer(int port) throws SocketException {
        super(port);

        // 给这个 dict 设置内容
        dict.put("cat", "小猫");
        dict.put("dog", "小狗");
        dict.put("fly", "廖飞洋");
        // 当然,这里可以无限多的设置键值对......
    }

    @Override
    public String process(String request) {
        // 查词典的过程
        return dict.getOrDefault(request, "当前单词没有查到结果!");
    }
}

运行结果

image-20231021113620823

端口冲突

一个端口只能被一个进程使用,如果有多个使用,就不被允许.

image-20231021125147691

Address already in use: Cannot bind
这里的 bind 是操作系统原生的API,这个API本身就是起到的“绑定IP+端口”,Address 表示的含义就相当于“IP+端口”.

TCP的相关 API 的使用

TCP提供的API主要是两个类:
ServerSocket专门给服务器使用的Socket对象
Socket是既会给客户端使用,也会给服务器使用

TCP不需要一个类来表示“TCP数据报”,因为TCP不是以数据报为单位进行传输的,是以字节的方式,进行流式传输.

ServerSocket API

~~ ServerSocket 是创建TCP服务端Socket的API

ServerSocket 构造方法

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket 方法

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket 对象,并基于该Socket建立与客户端的连接,否则阻塞等待相当于“接电话”,接了电话,会返回一个Socket对象,通过这个Socket对象和客户端进行沟通.
void close()关闭此套接字

Socket API

在服务器这边,是由accept返回的,在客户端这边,是由我们代码里构造的,构造的时候指定一个IP和端口号(此处的IP和端口号是服务器的IP和端口),有了这个信息,就能够和服务器建立连接了.

Socket 构造方法

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入
OutputStream getOutputStream()返回此套接字的输出流

InputStream getInputStream(),OutputStream getOutputStream():进一步通过Socket对象,获取到内部的流对象,借助流对象进行发送/接受.

TCP版本的回显服务器

相关代码

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fly(逐梦者)
 * Date: 2023-10-21
 * Time: 15:26
 */
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("启动服务器");
        while (true) {
            /* accept效果是"接收连接",前提是得有客户端来建立连接!
              客户端在构造Socket对象的时候,就会指定服务器的IP和端口.
              如果没有客户端来连接,此时accept就会阻塞.
             */
            Socket clientSocket = serverSocket.accept();
            // 使用这个 clientSocket和具体的客户端进行交流.
            processConnection(clientSocket);
        }

    }

    // 使用这个方法来处理一个连接
    // 这一个连接对应到一个客户端,但是这里可能会涉及到多次交互
    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        // 基于上述 socket 对象和客户端进行通信
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            // 由于要处理多个请求和响应,也是使用循环来进行的
            while (true){
                // 1.读取请求
                Scanner scanner = new Scanner(inputStream);
                if (!scanner.hasNext()){
                    // 没有下一个数据,说明读完了(客户端关闭了连接)
                    System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                // 注: 此处使用 next 是一直读取到换行符/空格/其他空白符结束,但是最终返回结果里不包含上述空白符.
                String request=scanner.next();
                // 2.根据请求构造响应
                String response=process(request);
                // 3.返回响应结果
                // outputStream 没有 write String 这样的功能,可以把 String 里的字节数组拿出来,进行写入
                PrintWriter printWriter=new PrintWriter(outputStream);
                // 此处使用 println 来写入,让结果中带有一个 \n,方便接受端来接受解析
                printWriter.println(response);
                // flush 用来刷新缓冲区,保证当前写入的数据,确实是发送出去了.
                printWriter.flush();
                System.out.printf("[%s %d] req: %s; resp: %s \n",
                        clientSocket.getInetAddress().toString(),
                        clientSocket.getPort(),
                        request,response);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 把 close 放到 finally 里面的,保证一定你能执行到!
            clientSocket.close();
        }
    }

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

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

image-20231021193510005
Socket clientSocket = serverSocket.accept();
processConnection(clientSocket);
这个代码中,用到一个clientSocket.此时任意一个客户端连上来,都会返回/创建一个Socket对象.(Socket就是文件)每次创建一个clientSocket对象,就要占用一个文件描述符表的位置.再加上因为每个客户端都有一个,此处的clientSocket的数量就会非常多,因此在使用完毕之后,就需要进行"释放".

代码缺陷: 当前的这个TCP server 有一个致命缺陷,一次只能处理一个客户端.

主要是主动发起请求的一方,就是服务器.只要是被动的一方,就是服务器.所以一个服务器即可是服务器,也可以是客户端.

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fly(逐梦者)
 * Date: 2023-10-21
 * Time: 18:48
 */
public class TcpEchoClient {
    private Socket socket=null;
    public TcpEchoClient(String serverIp,int serverPort) throws IOException {
        // Socket 构造方法,能够识别 点分十进制格式的IP地址,比DatagramPacket更方便.
        // new 这个对象的同时,就会进行 TCP 的连接操作.
        socket=new Socket(serverIp,serverPort);
    }
    public void start(){
        System.out.println("客户端启动!");
        Scanner scanner=new Scanner(System.in);
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()) {
            while (true){
                // 1.先从键盘读取用户输入的内容
                System.out.println(">");
                String request=scanner.next();
                if (request.equals("exit")){
                    System.out.println("goodbye");
                    break;
                }
                // 2.把读到的内容构造成请求,发送到服务器
                PrintWriter printWriter=new PrintWriter(outputStream);
                printWriter.println(request);
                // 此处加个 flush,保证数据确实发送
                printWriter.flush();
                // 3.读取服务器的响应
                Scanner respScanner = new Scanner(inputStream);
                String response = respScanner.next();
                // 4.把响应内容显示到界面上
                System.out.println(response);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

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

image-20231021200751756

运行结果

image-20231021200922413

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

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

相关文章

EtherCAT主站SDO读报文抓包分析

0 工具准备 1.EtherCAT主站 2.EtherCAT从站&#xff08;本文使用步进电机驱动器&#xff09; 3.Wireshark1 抓包分析 1.1 报文总览 本文读取从站1的对象字典&#xff0c;读取对象字典主索引为0x2000&#xff0c;子索引为0x00。主站通过发送SDO读报文实现对该对象字典的读取&…

python免杀初探

文章目录 loader基础知识loader参数介绍 evilhiding项目地址免杀方式修改加载器花指令混淆loader源码修改签名加壳远程条件触发修改ico的md5加密 loader基础知识 loader import ctypes #&#xff08;kali生成payload存放位置&#xff09; shellcode bytearray(b"shellc…

线上Timeout waiting for connection from pool问题分析和解决方案

目录 现象 理论分析 代码分析 解决方案 方案一:直接修改pollingConnectionManager 方案二:修改HttpClient 参考 现象 线上共有5个类似服务,但是只有流量较大的服务会出现成功率的问题。 问题的表现主要是在GetFile(fileId=AgACAgUAAxkDAAEbP1JlJPxyJM82phEKhYYZYfY9…

互联网Java工程师面试题·Java 面试篇·第三弹

目录 39、JRE、JDK、JVM 及 JIT 之间有什么不同&#xff1f; 40、解释 Java 堆空间及 GC&#xff1f; 41、你能保证 GC 执行吗&#xff1f; 42、怎么获取 Java 程序使用的内存&#xff1f;堆使用的百分比&#xff1f; 43、Java 中堆和栈有什么区别&#xff1f; 44、“ab”…

nodejs+vue中小学课程辅导系统-计算机毕业设计

这个中小学课程辅导系统的项目分为两种&#xff0c;普通用户和管理员。 二十一世纪&#xff0c;互联网已成为当今世界不可缺少的一部分&#xff0c;不仅加强人与人之间的联系&#xff0c;并且能够实现资源共享 , 我国人民的生活水平逐年提高&#xff0c;该系统利用面向目标群体…

容器技术基础

1. Linux Namespace和Cgroups 对于 Docker 等大多数 Linux 容器来说&#xff0c;Cgroups 技术是用来制造约束的主要手段&#xff0c;而 Namespace 技术则是用来修改进程视图的主要方法。 1.1 PID Namespace //Linux 系统正常创建线程 int pid clone(main_function, stack_s…

网络编程-java基础

两台电脑之间的通信形成了网络 最小的网络&#xff1a;局域网 校园网(局域网) 城域网(一个市) 广域网(全球) 为什么我发QQ你能收到&#xff0c;这是因为我发的消息实际上是发给了QQ服务器&#xff0c;并不是直接发给你的&#xff0c; 我是与QQ服务器进行通信的&#xff0c…

【C++】格式与实例化操作——[模板]详解(7)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一. 模板参数与模板参数列表1)模板参数…

JS学习-CryptoJS加密库

CryptoJS加密库 安装库 npm install crypto-js如下例子 对称加密 const CryptoJS require(crypto-js); //引入加密库 var str"123456" //md5加密 console.log(CryptoJS.MD5(str).toString()) var str2 CryptoJS.enc.Utf8.parse(str); //可以把字符串转成UTF-…

数据结构数组 Array 手写实现,扩容原理

数组数据结构 数组&#xff08;Array&#xff09;是一种线性表数据结构。它用一组连续的内存空间&#xff0c;来存储一组具有相同类型数据的集合。 数组的特点&#xff1a; 数组是相同数据类型的元素集合&#xff08;int 不能存放 double&#xff09;数组中各元素的存储是有先…

Xcode14创建github远程仓库Token

1.点击Create a Token on GitHub 2.在打开的网页中,登陆GitHub 3.点击生成Token 这是不能为空 4.Token创建成功如下: 5.复制Token到Xcode然后点击Sign In登陆 正在创建远程我仓库 正在将本地仓库代码推入远程仓库 创建成功

method.isAnnotationPresent(Xxx.class)一直为null

​​​​package com.dj.springtest.aspect;import com.dj.springtest.annotation.RequireRoles; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.s…

Linux中的shell编程

shell编程 重定向 cat >temp 输入内容到temp文件中&#xff0c;如果存在temp则覆盖&#xff0c;没有则新建 cat >>temp 追加内容 cat temp1>>temp2 将temp1中的内容追加到temp 命令执行控制符号 ; 一个命令行执行多条语句 命令替换符 1.双引号&#…

【软考】12.1 范围管理/进度管理

《范围管理》 项目需求的范围边界工作分解结构&#xff08;WBS&#xff09;&#xff1a;自上而下的分解结构 产品范围和项目范围 产品范围&#xff1a; a. 产品或服务应包含的功能 ——> 产品要求的描述 b. 判断是否完成&#xff1a;是否满足产品描述 项目范围&#xff1a;…

Hadoop3教程(三十二):(生产调优篇)NameNode故障恢复与集群的安全模式

文章目录 &#xff08;159&#xff09;NameNode故障处理&#xff08;160&#xff09;集群安全模式&磁盘修复集群安全模式磁盘修复等待安全模式 参考文献 &#xff08;159&#xff09;NameNode故障处理 如果NameNode进程挂了并且存储的数据也丢失了&#xff0c;如何恢复Nam…

基于nodejs+vue 中小学课程辅导系统

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

浏览器的渲染机制

渲染机制 浏览器的渲染机制一般分为以下几个步骤 处理 HTML 并构建 DOM 树。处理 CSS 构建 CSSOM 树。将 DOM 与 CSSOM 合并成一个渲染树。根据渲染树来布局&#xff0c;计算每个节点的位置。调用 GPU 绘制&#xff0c;合成图层&#xff0c;显示在屏幕上。 在构建 CSSOM 树时…

【模型推理优化学习笔记】张量并行和流水线并行简介

张量并行 当每个张量被分成多个块时&#xff0c;就会发生张量并行性&#xff0c;并且张量的每个块都可以放置在单独的 GPU 上。在计算过程中&#xff0c;每个块在不同的 GPU 上单独并行处理&#xff0c;并且可以通过组合来自多个 GPU 的结果来计算结果&#xff08;最终张量&am…

React环境初始化

环境初始化 学习目标&#xff1a; 能够独立使用React脚手架创建一个React项目 1.使用脚手架创建项目 官方文档&#xff1a;(https://create-react-app.bootcss.com/)    - 打开命令行窗口    - 执行命令      npx create-react-app projectName    说明&#xff1a…

Linux:权限是什么

本篇文章来简单介绍一下Linux操作系统中权限的基本概念和一些操作方法&#xff0c;对Linux权限有一个基本的了解&#xff0c;希望对大家学习Linux有所帮助。 目录 1.权限的概念 2.Linux权限管理 2.1 文件访问者的分类 2.2 文件类型与访问权限&#xff08;事物属性&#xff…