(考研湖科大教书匠计算机网络)第五章传输层-第八节2:TCP连接管理实践部分

news2024/11/15 11:32:49
  • 获取pdf:密码7281
  • 专栏目录首页:【专栏必读】考研湖科大教书匠计算机网络笔记导航

此部分为补充内容,主要使用Java实现TCP和UDP通信

一:UDP通信

(1)Java数据报套接字通信模型

Java UDP通信模型:Java中使用UDP协议通信,主要依靠一下两个类

  • DatagramSocket:创建UDP Socket
  • DatagramPacket:是UDP Socket发送和接受的数据报

一次发送和接收UDP数据报流程如下

在这里插入图片描述

多个请求流程如下

在这里插入图片描述

(2)API接口说明

A:DatagramSocket

DatagramSocket:用于构造UDP Socket,以发送和接收UDP数据报

构造方法如下

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

成员方法如下

方法签名方法说明
void receive(DatagramPacket p)从该Socket中接收数据报(如果未收到则会阻塞等待
void send(DatagramPacket p)由该Socket发送数据报(不会阻塞等待,直接发送
void close()关闭此Socket

B:DatagramPacket

DatagramPacket:是UDP Socket发送和接收的数据报

构造方法如下

方法签名方法说明
DatagramPacket(byet[] buf, int length)用于接收数据报,接收的数据保存在buf数组中,length指定接收长度
DatagramPacket(byet[] buf, int offset, int length, SocketAddress address)用于发送数据报,发送的数据为buf数组,范围为从0到lengthaddress是目的主机的IP和端口号

成员方法如下

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

(3)示例

  • 注意:这个功能比较简单,但主要目的是为了演示上面所讲API的用法

A:代码

服务端IP地址设置为127.0.0.1,也即本地环回,也即自己发自己收,数据会完整走一遍协议

服务端:UDPServer

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

public class UDPServer {
    // 构造DatagramSocket
    private DatagramSocket socket = null;

    public UDPServer(int port) throws SocketException {
        // 服务端需要绑定一个端口号
        socket = new DatagramSocket(port);
    }

    // 服务端启动
    public void start() throws IOException {
        System.out.println("服务器启动!");
        // 服务端随时等待接收客户端请求
        while (true) {
            /*
                 1. 接受请求并解析
                    构造一个DatagramPacket对象requestPacket用于接受客户端发来的数据报,保存在byte[]
                    为了方便查看信息,需要使用 requestPacket的getData()方法将其转换为String
             */
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(requestPacket);
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            /*
                2. 拿到客户端的请求request后,将其交给一个方法process进行处理,process方法会返回响应response
             */
            String response = process(request);
            /*
                3. 将响应回复给客户端
                   构造一个DatagramPacket对象responsePacket用于给客户端回复响应response ,response是String
                   所以需要使用用getBytes()方法将其转化为byte[]
                   客户端发来的requestPacket数据报中携带有客户端的Ip地址和端口号,使用getSocketAddress()获得
             */
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);

            // 打印信息
            System.out.println("【客户端IP: " + requestPacket.getAddress().toString()
                    + "客户端口号:" + requestPacket.getPort() + "】"
                    + ":\"" + request + "\"" + ", 服务端回复: " + "\"" + response + "\"");
        }
    }

    // 回显服务器,客户端发什么服务端就回复什么
    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        // 服务端监听9090端口
        UDPServer server = new UDPServer(9090);
        server.start();
    }
}

客户端:UDPClient

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

public class UDPClient {
    DatagramSocket socket = null;
    // 客户端需要指定好服务端的IP和端口号,然后构建一个Socket地址
    private SocketAddress ADDRESS = null;

    public UDPClient(String serverIP, int serverPort) throws SocketException {
        ADDRESS = new InetSocketAddress(serverIP, serverPort);
        socket = new DatagramSocket();
    }

    // 客户端启动
    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1. 读取客户端用户输入
            System.out.print("input: ");
            String request = scanner.next();

            /*
                2. 发送请求给服务端
                   构造一个DatagramPacket对象requestPacket用于给服务端发送数据报,注意需要将String转换为byte[]
                   同时传入服务端的ADDRESS(ip地址和port)
             */
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                   ADDRESS);
            socket.send(requestPacket);

            // 3. 从服务端获取响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());

            // 打印信息
            System.out.println("服务端回复:" + response);

        }
    }

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

B:效果展示

一个服务端一个客户端

在这里插入图片描述
一个服务端多个客户端

注意如果需要运行多个UDPClient实例,需要在Run/Debug Configurations中选中Allow multiple instances
在这里插入图片描述

这里启动三个客户端
在这里插入图片描述

C:分析

对于服务端(UDPServer类)

  • 构造方法( public UDPServer(int port)

    • 需要建立一个DatagramSocket并绑定一个指定的端口号port,也即 DatagramSocket socket =new DatagramSocket(port)。服务端绑定端口号的原因是因为程序运行在服务器上是确定的、可控的
  • 服务端处理逻辑(public void start()

    • ①:接受请求并解析

      • 需要构造一个DatagramPacket用于接受客户端发来的数据报,会保存在byte[]中,也即DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096)
      • 接受行为由socket完成,也即socket.receive(requestPacket)
      • 接受到的requestPacket 其类型为byte[],所以需要把它转为String以便于查看,也即String request = new String(requestPacket.getData(), 0, requestPacket.getLength())
    • ②:处理请求

      • 拿到解析后的request后,需要对该request进行处理(交给方法process),不同的业务逻辑会有不同的处理方法。这里我们只是简单的“回显”一下即可,也即客户端发什么服务端就回复什么
    • ③:将处理结果(响应)回复给客户端

      • 需要构造一个DatagramPacket用于给客户端回复响应response,在构造时要将类型为Stringrespnse转化为byte[],同时使用requestPacket.getSocketAddress()获取到客户端的IPport(因为服务端总要知道客户端的具体地址才能发送),也即DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress())
      • 发送行为由socket完成,也即socket.send(responsePacket);
    • ④:打印相关信息

  • main方法

    • 构造UDPServer对象,并绑定指定端口号,如9090,也即UDPServer server = new UDPServer(9090)
    • 启动服务端,也即server.start()

对于客户端(UDPClient类):

  • 构造方法(public UDPClient(String serverIP, int serverPort)

    • 需要建立一个DatagramSocket,但不指定端口号,也即DatagramSocket socket =new DatagramSocket()。客户端无需绑定端口号是因为客户端上运行状况复杂,端口号占用情况各不相同,无法保证所指定的端口号在数据报来临时一定是空闲的,所以这里让系统自动指定空闲端口号即可

    • 需要建立一个InetSocketAddress,传入服务端serverIPserverPort,也即SocketAddress ADDRESS = new InetSocketAddress(serverIP, serverPort),这里的serverPort就是服务端中所指定的那个port。之所以这样做是因为客户端发送时必须要知道服务端的IP地址和port

      • InetSocketAddressSocketAddress的子类
  • 客户端处理逻辑(public void start()

    • ①:读取客户端中用户的输入

      • 使用Scanner接受即可,也即String request = scanner.next()
    • ②:发送请求给服务端

      • 需要构造一个DatagramPacket给服务端发送数据报,注意需要将类型Stringrequest转化为byte[],同时传入服务端的ADDRESS。也即DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length, ADDRESS);
      • 发送行为由socket完成,也即socket.send(requestPacket)
    • ③:从服务端获取响应

      • 需要构造一个DatagramPacket用于接受服务端端发来的数据报,会保存在byte[]中,也即DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096)
      • 接受行为由socket完成,也即socket.receive(responsePacket)
      • 接受到的responsePacket 其类型为byte[],所以需要把它转为String以便于查看,也即String response = new String(responsePacket.getData(), 0, resoibsePacket.getLength())
    • ④:打印相关信息

  • main方法

    • 构造UDPClient对象,并给定服务端IPport,也即 UDPClient client = new UDPClient("127.0.0.1", 9090)
    • 启动客户端,也即client.start()

二:TCP通信

(1)Java流套接字通信模型

Java TCP通信模型:Java中使用TCP协议进行通信,主要依靠以下两个类

  • ServerSocket:是创建TCP服务端Socket的API
  • Socket API:是客户端Socket,或服务端中接收到客户端连接(accept方法)的请求后,返回服务端Socket

通信流程如下
在这里插入图片描述

(2)API接口说明

A:ServerSocket

ServerSocket:用于创建TCP服务端流套接字Socket

构造方法如下

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

成员方法如下

方法签名方法说明
Socket accept()开始监听端口,当有客户端连接后会返回一个服务端Socket对象,并基于该Socket 与客户端建立连接,否则阻塞等待
void close()关闭此套接字

B:Socket

Socket :是客户端的Socket(当然也会给服务端用,上面表格说过,当有客户端连接服务端后,会返回一个服务端Socket

构造方法如下

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

成员方法如下

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

(3)示例

  • 注意:这个功能比较简单,但主要目的是为了演示上面所讲API的用法

A:代码

服务端IP地址设置为127.0.0.1,也即本地环回,也即自己发自己收,数据会完整走一遍协议

服务端TCPServer:

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 TCPServer {
    // 创建监听套接字
    private ServerSocket listenSocket = null;

    public TCPServer(int port) throws IOException {
        // 监听套接字绑定指定端口
        listenSocket = new ServerSocket(port);
    }

    // 服务器启动
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true) {
            // 调用监听套接字的accept()连接客户端,并返回Socket类型的clientSocket
            // 将clientSocket传递给具体处理连接的方法processConnection()进行处理
            Socket clientSocket = listenSocket.accept();
            // 进行处理
            processConnection(clientSocket);
        }
    }
    // 用于处理连接
    private void processConnection(Socket clientSocket) throws IOException {
        System.out.println("【客户端IP: " + clientSocket.getInetAddress().toString()
                + "客户端口号:" + clientSocket.getPort() + "】"
                + "已上线");

        // 处理请求
        // 打开inputStream和outputStream
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            while (true) {
                // 1. 读取请求并解析
                Scanner scanner = new Scanner(inputStream);
                if (!scanner.hasNext()) {
                    // 如果读完了那么连接可以断开了
                    System.out.println("【客户端IP: " + clientSocket.getInetAddress().toString()
                            + "客户端口号:" + clientSocket.getPort() + "】"
                            + "下线");
                    break;
                }
                String request = scanner.next();
                // 2. 根据请求计算响应,具体处理函数为process
                String response = process(request);

                // 3. 响应回复给客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                printWriter.flush();

                // 打印信息
                System.out.println("【客户端IP: " + clientSocket.getInetAddress().toString()
                        + "客户端口号:" + clientSocket.getPort() + "】"
                        + ":\"" + request + "\"" + ", 服务端回复: " + "\"" + response + "\"");
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭套接字
            // listenSocket在TCP服务端程序中只有一个,所以不太可能把文件描述符占满
            // 而clientSocket 每遇到一个客户端都要创建一个,所以一定要注意关闭
            clientSocket.close();
        }
     }

     // 业务逻辑函数
    public String process(String request) {
        return request;
    }

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

客户端TPCClient:

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 TCPClient {
    // 建立Socket对象
    private Socket socket = null;

    public TCPClient(String serverIP, int serverPort) throws IOException {
        // 指定服务端IP和端口号
        socket = new Socket(serverIP, serverPort);
    }

    // 客户端启动
    public void start () throws IOException {
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            while (true) {
                // 1. 获取用户输入
                System.out.print("input: ");
                String request = scanner.next();
                // 2. 发送请求给服务端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                printWriter.flush();
                // 3. 从服务端获得响应
                Scanner responseScanner = new Scanner(inputStream);
                String response = responseScanner.next();

                // 打印信息
                System.out.println("服务端回复:" + response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

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

}

B:效果展示

在这里插入图片描述

C:分析

对于服务端(TCPServer类)

  • 构造方法(public TCPServer(int port)

    • 需要建立一个ServerSocket类型的监听套接字,用于监听客户端的请求连接,也即private ServerSocket listenSocket = new ServerSocket(port)
  • 服务端处理逻辑(public void start()

    • 不断循环一直监听客户端的连接,当有客户端连接之后监听套接字会返回Socket类型的套接字用于处理这个连接,也即Socket clientSocket = listenSocket.accept()
    • 具体处理连接的过程交由processConnection()方法进行,也即processConnection(ClientSocket)
  • 服务端处理连接(private void processConnection(Socket clientSocket)

    • ①:打开套接字的输入流和输出流

      • clientSocket里的请求内容保存在其InputStream中,最终服务端回复响应时要将该响应写入到其OutputStream中,也即InputStream inputStream = clientSocket.getInputStream()OutputStream outputStream = clientSocket.getOutputStream()
    • ②:读取InputStream中的请求并解析

      • 使用Scanner进行读取比较方便,也即Scanner scanner = new Scanner(inputStream)
      • 读取时注意随时判断是否读取完毕,如果读取完毕表示客户端可以下线了
      • 读取好的请求保存在request中,也即String request = scanner.next()
    • ③:根据请求得到响应

      • request后,需要对该request进行处理(交给方法process),不同的业务逻辑会有不同的处理方法。这里我们只是简单的“回显”一下即可,也即客户端发什么服务端就回复什么
    • ④:将响应写入到OutputStream

      • 使用PrintWriter 写入比较方便,也即PrintWriter printWriter = new PrintWriter(outputStream)printWriter.println(response)
      • 写入完成之后必要忘记刷新一下,也即printWriter.flush()
    • ⑤:打印相关信息

    • ⑥:关闭clientSocket套接字

      • listenSocket在TCP服务端程序中只有一个,所以不太可能把文件描述符占满,而clientSocket 每遇到一个客户端都要创建一个,所以一定要注意关闭,也即 clientSocket.close()
  • main方法

    • 构造TCPServer对象,并绑定指定端口号,如9090,也即TCPServer server = new TCPServer(9090)
    • 启动服务端,也即server.start()

对于服务端(TCPClient类)

  • 构造方法(public TCPClient(String serverIP, int serverPort)

    • 需要建立一个Socket类型的套接字,并传入服务端IPPort,也即private Socket socket = new Socket(serverIP, serverPort)
  • 客户端处理逻辑(public void start ()

    • ①:打开套接字的输入流和输出流

      • 客户端会把它的请求写入到InputStream中,服务端回复响应后客户端会从 OutputStream 中读取,也即InputStream inputStream = socket.getInputStream()OutputStream outputStream = socket.getOutputStream()
    • ②:读取客户端用户输入并构造请求

      • 使用Scanner接受即可,也即String request = scanner.next()
    • ③:将请求写入到OutputStream

      • 使用PrintWriter 写入比较方便,也即PrintWriter printWriter = new PrintWriter(outputStream)printWriter.println(request)
      • 写入完成之后必要忘记刷新一下,也即printWriter.flush()
    • ④:读取InputStream中的响应

      • 使用Scanner进行读取比较方便,也即Scanner responseScanner = new Scanner(inputStream)String response = responseScanner.next()
    • ⑤:打印相关信息

  • main方法

    • 构造TCPClient对象,并给定服务端IPPort,也即TCPClient client = new TCPClient("127.0.0.1", 9090)
    • 启动客户端,也即client.start()

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

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

相关文章

算法笔记(十)—— 哈希函数和哈希表

认识哈希函数和哈希表的实现 哈希函数 哈希函数:输入域无穷,输出域(哈希值)相对有限 哈希函数:相同的输入一定会返回相同的输出值 由于输入域的无限和输出域的有限,不同的输入可能会返回相同的输出&…

配置Tomcat性能优化

配置Tomcat性能优化 📒博客主页: 微笑的段嘉许博客主页 💻微信公众号:微笑的段嘉许 🎉欢迎关注🔎点赞👍收藏⭐留言📝 📌本文由微笑的段嘉许原创! &#x1f4…

常用类(五)System类

(1)System类常见方法和案例: (1)exit:退出当前程序 我们设计的代码如下所示: package com.ypl.System_;public class System_ {public static void main(String[] args) {//exit: 退出当前程序System.out.println("ok1"…

详解C++的类型转换

文章目录前言一、C语言中的类型转换二、为什么C需要四种转换三、C强制类型转换3.1 static_cast3.2 reinterpret_cast3.3 const_cast3.4 dynamic_cast四、RTTI总结前言 在C语言的类型转换有一个非常大的坑,有好多悄悄地转换,有时候把我们转换的就蒙了,因为C要兼容C语言,所以C就…

docker容器单机网络

前言 通过文章 容器的本质可知,容器只是一个进程,而容器所能看到的网络栈,是隔离在自己的 Network Namespace 中。docker 容器单机网络支持四种网络模式,也都是基于 Network Namespace 实现的。本文主要是介绍这四种模式的使用方…

四、actions处理异步行为和调用

四、actions处理异步行为和调用 action:装方法的一个对象。 使用场景:在Vuex运行的环节中,有异步操作——>就必须经过action mutations不能进行异步操作。 最常用的案例:异步请求获取数据 使用方式: 组件中使用a…

移动WEB开发一、基础知识

零、文章目录 文章地址 个人博客-CSDN地址:https://blog.csdn.net/liyou123456789个人博客-GiteePages:https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee:https://gitee.com/bluecusliyou/TechLearnGithub:https:…

git ssh配置

ssh配置 执行以下命令进行配置 git config --global user.name “这里换上你的用户名” git config --global user.email “这里换上你的邮箱” 执行以下命令生成秘钥: ssh-keygen -t rsa -C “这里换上你的邮箱” 执行命令后需要进行3次或4次确认。直接全部回车就…

基于 ChatGPT 3.5 和 Bing 搜索引擎的会话式搜索引擎 Perplexity 初体验

一、背景 最近 ChatGPT 非常火爆,但是基础版经常访问失败,于是乎想找一些替代品。 搜到了一个 基于 ChatGPT 3.5 和 Bing 搜索的会话式搜索引擎 Perplexity 体验了下非常不错,值得推荐。 二、联系和区别 2.1 联系 官网在外媒社交媒体上…

三、NetworkX工具包实战3——特征工程【CS224W】(Datawhale组队学习)

开源内容:https://github.com/TommyZihao/zihao_course/tree/main/CS224W 子豪兄B 站视频:https://space.bilibili.com/1900783/channel/collectiondetail?sid915098 斯坦福官方课程主页:https://web.stanford.edu/class/cs224w NetworkX…

【安卓开发】安卓广播机制

读书笔记系列(第一行代码) 5.1 广播机制简介 标准广播:完全异步执行,广播发出后,所有广播接收器几乎都同一时刻收到这条广播(无法被截断)有序广播:同步执行,广播发出后…

优秀!19年后,它再次成为TIOBE年度编程语言

新年伊始,TIOBE发布了2022年度编程语言,C时隔19年再度登顶,成为2022年最受欢迎的编程语言。TIOBE在2003年首次统计编程语言的流行指数时,C便成为年度编程语言。2022年,C获得了最高的人气4.62%,紧随其后的是…

maven打包顺序与jvm类加载顺序

背景:一次dev测试过程中,发现代码中关于jsr303的校验失效,校验类如下,会报一个莫名其妙的运行时错误;遂进行排查。import javax.validation.constraints.NotBlank;Data Accessors(chain true) public class Demo {Not…

为什么会有跨域问题,代理是怎么解决的?

📖 文章导航关于跨域问题同源策略跨域资源共享解决方案前端代理后端服务端代理关于跨域问题 同源策略 同源策略(Same-origin policy)是浏览器中一个重要的安全策略,它用于限制不同源之间的资源交互。其目的是为了帮助阻隔恶意文…

由浅入深,一起来刷Java高级开发岗面试指南,面试必定无忧!

前言 我只想面个CV工程师,面试官偏偏让我挑战造火箭工程师,加上今年这个情况更是前后两男,但再难苟且的生活还要继续,饭碗还是要继续找的。在最近的面试中我一直在总结,每次面试回来也都会复盘,下面是我根…

Dubbo之SpringBoot启动源码详解

需要前置知识,了解spring源码,springboot自动加载机制等 DubboBootstrap启动 详细信息可看 学习Dubbo源码需要了解的基础内容源码详解 DubboBootstrap 启动所需要的信息 添加应用程序配置添加注册中心配置添加协议配置添加服务配置启动 SpringBoot启…

广东MES系统实施过程中的要点和难点

MES系统已经成为企业目前实施的焦点。但是MES系统又分为很多的种类,对企业之间则是很难选择的,因为大部分的企业对MES系统的要点和难点并不清楚,而今天就让先达盈致的小编带大家了解一下广东MES系统实施过程中的要点和难点。MES系统是实现企业…

戴尔T5810电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网,转载需注明出处。硬件型号驱动情况主板戴尔T5810,C610/612芯片处理器英特尔至强E5-2620 v3已驱动内存12 GB已驱动硬盘500GB WD Blue Solid State Drive & 2TB Seagate Mobile Hard Drive (Upgraded)已驱动显卡RX 570 4Gb已驱…

october-cms

环境准备 靶机链接:百度网盘 请输入提取码 提取码:3e4s 虚拟机网络链接模式:桥接模式 攻击机系统:kali linux 2021.1 信息收集 1.探测目标靶机ip。 2.探测靶机开放端口和服务情况。 漏洞探测 1.访问网页 2.用dirsearch扫描…

用javascript分类刷leetcode15.链表(图文视频讲解)

链表操作如下图: 动画过大,点击查看 时间复杂度: prepend: O(1)append: 如果已知尾节点O(1),否则需要遍历到尾节点,然后加入新节点O(n)insert: 插入到已知节点的后面O(1),需要先查找后插入O(n)lookup: O…