IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> IP归属地在线查询平台 -> 正文阅读

[网络协议]IP归属地在线查询平台

一、项目介绍

1、背景

根据IP得到位置,加标签

进行大数据分析,比如淘宝推荐等提供优质数据

? ? ? ? ? ? ?www.ip.cn 等 查询IP

2、需求

? ? ?

IP 分析 归属地信息 , 查找在毫秒内完成

IP地址库,公网都是开放的

IANA : 国际组织,负责公网IP维护分发

3、技术栈

Eclipse ,JavaSE中面向对象、IO流、二分法算法、Base64编码、工具类封装

4、目标

?

通过开发IP地址归属地查询平台,我们需要对JavaSE综合技术有所提升,增强实战能力。学习完该项目我们应该具备如下能力:

1 面向对象程序设计

2 工具类封装与使用写法

3 文件IO流

4 字符串处理

5 二分法查找

6 IP地址的不同形式的使用

二、主要思路

? ? ? ?

1 程序中读取内容

2 解析IP字符串,进行结构化处理

3 封装工具类

4 接口API

? ? ? ? ? 入参 : IP

? ? ? ? ? ?出参 : 归属地

应用开发类项目

C/S结构,需要有特定的客户端,比如QQ,微信,eclipse

Web开发类项目

B/S结构为主.通过网页形式访问的在线系统,比如各类官网,各类管理系统等

中小型项目研发标准流程

1 需求概述-需求描述:说清楚你为什么做这个项目

根据IP获取归属地

2 需求分析 :

根据需求概述,用技术角度考虑一下,是否可行

三方面 : 1 输入 , 2? 输出 , 3 必备物料(地址库)

输入 : 给定一个任意的合法IP地址

输出 : 返回IP地址对应的地址库

3 开发步骤

1 读取IP地址库

2 解析地址库的信息,进行结构化处理

3 将对象保存到list中

4 进行二分法查找,提高效率

5 对外提供访问的接口

6 测试

4 细节开发与风险控制

5 BUG修复,调优,标准化

6 正式上线

7 项目总结-项目复盘

  • ?三、代码开发

  1. ?无脑读取文件

?

2. 文本文件读取工具类

抽象工具类

1 通过编码,实现输入与输出

2 抽象输入与输出,形成方法入参和出参

3 工具类代码实现并测试

2.1? 工具类编码

?2.2? 工具类测试

3.结构化?

结构化 : 当我们知道第一个数据的格式的时候,那么第二个的数据格式就已经确定了,有规律可循,方便操作

根据非结构化数据,找到对应的规则,并创建对应的实体类进行封装,转换为结构化数

4.?抽象实体类并保存数据?

4.1 实体类

?

4.2? 拆分数据为三列

?

5. 封装业务类DataProcessManager

5.1? 封装数据集合

// 1 文件路径

????????????????? String ipLibrayPath = "ip_location_relation.txt";

????????????????? String encoding = "UTF-8";

????????????????? // 保存数据对象

????????????????? List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

????????????????? try {

????????????????????????? List<String> lineList = FileOperatorUtil.getLineList(ipLibrayPath,

??????????????????????????????????????????? encoding);

????????????????????????? for (String string : lineList) {

?????????????????????????????????? // 判断是否是空行

?????????????????????????????????? if (string==null || string.trim().equals("")) {

??????????????????????????????????????????? continue;

?????????????????????????????????? }

?????????????????????????????????? // 分割为数组

?????????????????????????????????? String[] columnArray = string.split("??????? ");

?????????????????????????????????? // 获取起始IP

?????????????????????????????????? String startIP = columnArray[0];

?????????????????????????????????? // 获取结束IP

?????????????????????????????????? String endIP = columnArray[1];

?????????????????????????????????? // 获取归属地

?????????????????????????????????? String location = columnArray[2];

?????????????????????????????????? // 封装到对象中

?????????????????????????????????? IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(startIP, endIP, location);

?????????????????????????????????? // 添加到集合中

?????????????????????????????????? ipAndLocationPojos.add(ipAndLocationPojo);

????????????????????????? }

????????????????????????? // 遍历测试

????????????????????????? for (IPAndLocationPojo ip : ipAndLocationPojos) {

?????????????????????????????????? System.out.println(ip);

????????????????????????? }

????????????????? } catch (IOException e) {

????????????????????????? e.printStackTrace();

????????????????? }

5.2 封装为管理类

public class DataProcessManager {

???????? /**

???????? ?* 结构化数据集合

???????? ?*

???????? ?* @param filePath

???????? ?* @param encoding

???????? ?* @return

???????? ?* @throws IOException

???????? ?*/

???????? public static List<IPAndLocationPojo> getPojoList(String filePath,

????????????????????????? String encoding) throws IOException {

????????????????? // 保存数据对象

????????????????? List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

????????????????? List<String> lineList = FileOperatorUtil

?????????????????????????????????? .getLineList(filePath, encoding);

????????????????? for (String string : lineList) {

????????????????????????? // 判断是否是空行

????????????????????????? if (string == null || string.trim().equals("")) {

?????????????????????????????????? continue;

????????????????????????? }

????????????????????????? // 分割为数组

????????????????????????? String[] columnArray = string.split("??????? ");

????????????????????????? // 获取起始IP

????????????????????????? String startIP = columnArray[0];

????????????????????????? // 获取结束IP

????????????????????????? String endIP = columnArray[1];

????????????????????????? // 获取归属地

????????????????????????? String location = columnArray[2];

????????????????????????? // 封装到对象中

????????????????????????? IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(

??????????????????????????????????????????? startIP, endIP, location);

????????????????????????? // 添加到集合中

????????????????????????? ipAndLocationPojos.add(ipAndLocationPojo);

????????????????? }

????????????????? return ipAndLocationPojos;

???????? }

}

5.3 测试封装类的方法

6.结构化集合转换为数组,toArray?

public class TestListToArray_01 {

???????? public static void main(String[] args) {

????????????????? List<String> list = new ArrayList<String>();

????????????????? list.add("a");

????????????????? list.add("b");

????????????????? list.add("c");

????????????????? String[] strs = new String[list.size()];

????????????????? list.toArray(strs);

????????????????? for (String string : strs) {

????????????????????????? System.out.println(string);

????????????????? }

????????????????? // 结构化数据集合转数组

????????????????? // 1 文件路径

????????????????? String ipLibrayPath = "ip_location_relation.txt";

????????????????? String encoding = "UTF-8";

????????????????? // 保存数据对象

????????????????? try {

????????????????????????? List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager

??????????????????????????????????????????? .getPojoList(ipLibrayPath, encoding);

????????????????????????? IPAndLocationPojo[] ipAndLocationPojoArray = new IPAndLocationPojo[ipAndLocationPojos

??????????????????????????????????????????? .size()];

????????????????????????? ipAndLocationPojos.toArray(ipAndLocationPojoArray);

????????????????????????? for (IPAndLocationPojo ipAndLocationPojo : ipAndLocationPojoArray) {

?????????????????????????????????? System.out.println(ipAndLocationPojo);

????????????????????????? }

????????????????? } catch (IOException e) {

????????????????????????? e.printStackTrace();

????????????????? }

???????? }

}

7.对象数组进行排序

7.1 实现排序

1 自定义实现

冒泡排序

选择排序

2 工具类

Collections

Arrays

一般不需要自己写,使用工具即可

7.2? 排序注意事项

被排序的对象必须具备可比性

1 实现Comparable接口

2 实现 Comparator接口

public class TestArraySort_01 {

???????? public static void main(String[] args) {

????????????????? // 基本类型

????????????????? int[] intArray = { 10, 6, 8, 9, 3, 15 };

????????????????? Arrays.sort(intArray);

????????????????? for (int i : intArray) {

????????????????????????? System.out.println(i);

????????????????? }

????????????????? // 引用类型 按照年龄升序

????????????????? User[] users = { new User(18, "张三1"), new User(19, "张三2"),

?????????????????????????????????? new User(15, "张三3"), new User(17, "张三4") };

????????????????? Arrays.sort(users);

????????????????? for (User user : users) {

????????????????????????? System.out.println(user);

????????????????? }

???????? }

}

class User implements Comparable<User> {

???????? private int age;

???????? private String name;

???????? public int getAge() {

????????????????? return age;

???????? }

???????? public void setAge(int age) {

????????????????? this.age = age;

???????? }

???????? public String getName() {

????????????????? return name;

???????? }

???????? public void setName(String name) {

????????????????? this.name = name;

???????? }

???????? public User(int age, String name) {

????????????????? super();

????????????????? this.age = age;

????????????????? this.name = name;

???????? }

???????? public User() {

????????????????? super();

???????? }

???????? @Override

???????? public String toString() {

????????????????? return "User [age=" + age + ", name=" + name + "]";

???????? }

???????? @Override

???????? public int compareTo(User o) {

????????????????? // 返回大于0 往后放

????????????????? // 返回小于0 往前放

????????????????? // 返回0 相等

????????????????? return this.age - o.age;

???????? }

}

7.3? 业务问题

上面已经通过测试,解决了技术问题,下面就是业务问题

我们比较肯定是IP,我们的IP地址没有办法使用字符串进行比较,因为字符串比较的ASCII码进行比较的

比如 1.1.6.2 和 1.1.125.1

看上去 肯定是 125大于 6? 但是按ASCII码进行比较的话 是 6 大于 125

所以 我们需要把IP进行转换

public class IPUtil {

???????? public static void main(String[] args) {

????????????????? String ip = "126.56.78.59";

????????????????? long ipLong = ipToLong(ip);

????????????????? System.out.println(ipLong);

????????????????? System.out.println(longToIP(ipLong));

???????? }

???????? /**

???????? ?* 将127.0.0.1形式的IP地址转换成十进制整数,这里没有进行任何错误处理

???????? ?* 通过左移位操作(<<)给每一段的数字加权,第一段的权为2的24次方,第二段的权为2的16次方,第三段的权为2的8次方,最后一段的权为1

???????? ?*/

???????? public static long ipToLong(String ipaddress) {

????????????????? long[] ip = new long[4];

????????????????? // 先找到IP地址字符串中.的位置

????????????????? int position1 = ipaddress.indexOf(".");

????????????????? int position2 = ipaddress.indexOf(".", position1 + 1);

????????????????? int position3 = ipaddress.indexOf(".", position2 + 1);

????????????????? // 将每个.之间的字符串转换成整型

????????????????? ip[0] = Long.parseLong(ipaddress.substring(0, position1));

????????????????? ip[1] = Long.parseLong(ipaddress.substring(position1 + 1, position2));

????????????????? ip[2] = Long.parseLong(ipaddress.substring(position2 + 1, position3));

????????????????? ip[3] = Long.parseLong(ipaddress.substring(position3 + 1));

????????????????? return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];

???????? }

???????? /**

???????? ?* 将十进制整数形式转换成127.0.0.1形式的ip地址 将整数值进行右移位操作(>>>),右移24位,右移时高位补0,得到的数字即为第一段IP。

???????? ?* 通过与操作符(&)将整数值的高8位设为0,再右移16位,得到的数字即为第二段IP。

???????? ?* 通过与操作符吧整数值的高16位设为0,再右移8位,得到的数字即为第三段IP。 通过与操作符吧整数值的高24位设为0,得到的数字即为第四段IP。

???????? ?*/

???????? public static String longToIP(long ipaddress) {

????????????????? StringBuffer sb = new StringBuffer("");

????????????????? // 直接右移24位

????????????????? sb.append(String.valueOf((ipaddress >>> 24)));

????????????????? sb.append(".");

????????????????? // 将高8位置0,然后右移16位

????????????????? sb.append(String.valueOf((ipaddress & 0x00FFFFFF) >>> 16));

????????????????? sb.append(".");

????????????????? // 将高16位置0,然后右移8位

????????????????? sb.append(String.valueOf((ipaddress & 0x0000FFFF) >>> 8));

????????????????? sb.append(".");

????????????????? // 将高24位置0

????????????????? sb.append(String.valueOf((ipaddress & 0x000000FF)));

????????????????? return sb.toString();

???????? }

}

7.4? ?实体类中衍生两个字段

上面可以把IP地址转换为long类型,方便进行排序比较

那么我们有起始IP和结束IP , 另外转换之后的长整型的值,也是需要保存起来的,和对应的IP字段需要一一对应

所以需要在对应的IP实体类中,再添加两个成员变量,分别保存转换之后的long值

?通过构造方法对long类赋值

?完整的实体类

public class IPAndLocationPojo implements Comparable<IPAndLocationPojo> {

???????? // 衍生字段,用于保存IP对应的long值

???????? private long startIPLong;

???????? private long endIPLong;

???????? /**

???????? ?* 起始IP

???????? ?*/

???????? private String startIP;

???????? /**

???????? ?* 结束IP

???????? ?*/

???????? private String endIP;

???????? /**

???????? ?* 归属地

???????? ?*/

???????? private String location;

???????? @Override

???????? public int compareTo(IPAndLocationPojo o) {

????????????????? long status = this.startIPLong - o.startIPLong;

????????????????? // 不能强制转换 , 如果两个值相差 2147483647的话,转换为int之后 得到负数

????????????????? // return (int) (this.startIPLong - o.startIPLong);

????????????????? return status > 0 ? 1 : 0;

???????? }

???????? public String getStartIP() {

????????????????? return startIP;

???????? }

???????? public long getStartIPLong() {

????????????????? return startIPLong;

???????? }

???????? public void setStartIPLong(long startIPLong) {

????????????????? this.startIPLong = startIPLong;

???????? }

???????? public long getEndIPLong() {

????????????????? return endIPLong;

???????? }

???????? public void setEndIPLong(long endIPLong) {

????????????????? this.endIPLong = endIPLong;

???????? }

???????? public void setStartIP(String startIP) {

????????????????? this.startIP = startIP;

???????? }

???????? public String getEndIP() {

????????????????? return endIP;

???????? }

???????? public void setEndIP(String endIP) {

????????????????? this.endIP = endIP;

???????? }

???????? public String getLocation() {

????????????????? return location;

???????? }

???????? public void setLocation(String location) {

????????????????? this.location = location;

???????? }

???????? public IPAndLocationPojo(String startIP, String endIP, String location) {

????????????????? super();

????????????????? this.startIP = startIP;

????????????????? this.endIP = endIP;

????????????????? this.location = location;

????????????????? // 对长整型赋值

????????????????? this.startIPLong = IPUtil.ipToLong(startIP);

????????????????? this.endIPLong = IPUtil.ipToLong(endIP);

???????? }

???????? public IPAndLocationPojo() {

????????????????? super();

???????? }

???????? @Override

???????? public String toString() {

????????????????? return "IPAndLocationPojo [startIP=" + startIP + ", endIP=" + endIP

?????????????????????????????????? + ", location=" + location + "]";

???????? }

}

7.5? 测试pojo排序

上面通过两个衍生字段已经让实体类拥有了排序功能,但是还没有进行排序

?7.6 封装排序方法

?7.7 测试

?8.二分法查询

上面已经把结构化数据进行排序,下一步就是二分法查询

// 1 确定起始和结束位置及中间位置

????????????????? // 2 如果目标数据小于中间数据,起始位置不变,结束位置为 中间位置-1 , 重新生成中间位置

????????????????? // 3 如果目标数据大于中间数据,结束位置不变,起始位置为 中间位置+1 , 重新生成中间位置

????????????????? // 4 如果目标数据等于中间数据, 终止,中间位置则是对应的下标

????????????????? // 5 如果起始位置 大于 结束位置 说明不存在

8.1? 基本类型

public class TestBinaraySearch_01 {

???????? public static void main(String[] args) {

????????????????? test1();

???????? }

???????? public static void test1() {

????????????????? // 1 确定起始和结束位置及中间位置

????????????????? // 2 如果目标数据小于中间数据,起始位置不变,结束位置为 中间位置-1 , 重新生成中间位置

????????????????? // 3 如果目标数据大于中间数据,结束位置不变,起始位置为 中间位置+1 , 重新生成中间位置

????????????????? // 4 如果目标数据等于中间数据, 终止,中间位置则是对应的下标

????????????????? // 5 如果起始位置 大于 结束位置 说明不存在

????????????????? int[] arr = { 1, 2, 3, 4, 7, 8, 9, 11, 15, 16, 18, 21, 26, 33, 55 };

????????????????? int target = 19;

????????????????? int startIndex = 0;

????????????????? int endIndex = arr.length - 1;

????????????????? int m = (startIndex + endIndex) / 2;

????????????????? while (startIndex <= endIndex) {

????????????????????????? if (target == arr[m]) {

?????????????????????????????????? System.out.println(target + " 在 " + m + " 位上");

?????????????????????????????????? return;

????????????????? ???????? }

????????????????????????? if (target < arr[m]) {

?????????????????????????????????? endIndex = m - 1;

????????????????????????? } else {

?????????????????????????????????? startIndex = m + 1;

????????????????????????? }

????????????????????????? m = (startIndex + endIndex) / 2;

????????????????? }

????????????????? System.out.println(target+" 不存在");

???????? }

}

8.2? 复杂类型

?9.IP地址对象二分法

9.1? 编码实现

public static void test3() throws IOException {

????????????????? // 1 文件路径

????????????????? String ipLibrayPath = "ip_location_relation.txt";

????????????????? String encoding = "UTF-8";

????????????????? // 保存数据对象

????????????????? List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager

?????????????????????????????????? .getPojoList(ipLibrayPath, encoding);

????????????????? // 转数组并排序

????????????????? IPAndLocationPojo[] ipAndLocationPojoArray = DataProcessManager

?????????????????????????????????? .convertListToArraySort(ipAndLocationPojos);

????????????????? // 目标数据是IP

????????????????? String targetIP = "1226.44.58.127";

????????????????? // 把IP转换为long

????????????????? long targetIPLong = IPUtil.ipToLong(targetIP);

????????????????? int startIndex = 0;

????????????????? int endIndex = ipAndLocationPojoArray.length - 1;

????????????????? int m = (startIndex + endIndex) / 2;

????????????????? /**

????????????????? ?* 如果 小于 起始IP? 找前面

????????????????? ?*

????????????????? ?* 如果 大于 起始IP 找后面

????????????????? ?*

????????????????? ?* 如果 大于等于起始IP且 小于等于 结束IP 则说明找到了

????????????????? ?*/

????????????????? while (startIndex <= endIndex) {

????????????????????????? if (targetIPLong >= ipAndLocationPojoArray[m].getStartIPLong() && targetIPLong <= ipAndLocationPojoArray[m].getEndIPLong()) {

?????????????????????????????????? System.out.println(targetIP + " 在 " + ipAndLocationPojoArray[m].getLocation());

?????????????????????????????????? return;

????????????????????????? }

????????????????????????? if (targetIPLong < ipAndLocationPojoArray[m].getStartIPLong()) {

?????????????????????????????????? endIndex = m - 1;

????????????????????????? } else {

?????????????????????????????????? startIndex = m + 1;

????????????????????????? }

????????????????????????? m = (startIndex + endIndex) / 2;

????????????????? }

????????????????? System.out.println(targetIP + " 不存在");

???????? }

9.2? 封装

public class DataProcessManager {

???????? /**

???????? ?* 二分法查找,入参是IP和数组,出参是对应的索引,找不到返回-1

???????? ?*

???????? ?* @param ipAndLocationPojoArray

???????? ?* @param targetIP

???????? ?* @return

???????? ?* @throws IOException

???????? ?*/

???????? public static int binaraySeach(IPAndLocationPojo[] ipAndLocationPojoArray,

????????????????????????? String targetIP) throws IOException {

????????????????? // 把IP转换为long

????????????????? long targetIPLong = IPUtil.ipToLong(targetIP);

????????????????? int startIndex = 0;

????????????????? int endIndex = ipAndLocationPojoArray.length - 1;

????????????????? int m = (startIndex + endIndex) / 2;

????????????????? /**

????????????????? ?* 如果 小于 起始IP 找前面

????????????????? ?*

????????????????? ?* 如果 大于 起始IP 找后面

????????????????? ?*

????????????????? ?* 如果 大于等于起始IP且 小于等于 结束IP 则说明找到了

????????????????? ?*/

????????????????? while (startIndex <= endIndex) {

????????????????????????? if (targetIPLong >= ipAndLocationPojoArray[m].getStartIPLong()

?????????????????????????????????????????? && targetIPLong <= ipAndLocationPojoArray[m].getEndIPLong()) {

?????????????????????????????????? return m;

????????????????????????? }

????????????????????????? if (targetIPLong < ipAndLocationPojoArray[m].getStartIPLong()) {

?????????????????????????????????? endIndex = m - 1;

????????????????????????? } else {

?????????????????????????????????? startIndex = m + 1;

????????????????????????? }

????????????????????????? m = (startIndex + endIndex) / 2;

????????????????? }

????????????????? return -1;

???????? }

9.3 测试

?10? 工具类封装

10.1 编码

上面已经把二分法完成,已经可以实现功能了,测试代码就相当于客户端

但是客户端现在需要知道的数据还有点多,比如IP地址库文件名,比如字符编码等

这些都是客户无感的,客户只关心 IP和归属地,我把IP给你,你把归属地给我,就行了

所以此时 我们需要对外提供一个方法,只有入参和出参

public class DataProcessManager {

???????? /**

???????? ?* 对外提供的接口,入参是IP,出参是归属地

???????? ?*

???????? ?* @param ip

???????? ?* @return

???????? ?*/

???????? public static String getLocation(String ip) {

????????????????? // 1 文件路径

????????????????? String ipLibrayPath = "ip_location_relation.txt";

????????????????? String encoding = "UTF-8";

????????????????? // 保存数据对象

????????????????? List<IPAndLocationPojo> ipAndLocationPojos = null;

????????????????? IPAndLocationPojo[] ipAndLocationPojoArray = null;

????????????????? try {

????????????????????????? // 获取数据

????????????????????????? ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrayPath,

??????????????????????????????????????????? encoding);

????????????????????????? // 转数组并排序

????????????????????????? ipAndLocationPojoArray = DataProcessManager

??????????????????????????????????????????? .convertListToArraySort(ipAndLocationPojos);

????????????????? } catch (IOException e) {

????????????????????????? e.printStackTrace();

????????????????? }

????????????????? // 二分法查找

????????????????? int index = DataProcessManager.binaraySeach(ipAndLocationPojoArray, ip);

????????????????? // 判断是否找到

????????????????? if (index == -1) {

????????????????????????? return null;

????????????????? } else {

????????????????????????? return ipAndLocationPojoArray[index].getLocation();

????????????????? }

???????? }

10.2 测试

?10.3? 优化

现在getLocation方法,每次调用都会去读取IP地址库,并且转换为结构化数据,然后进行排序

这样效率很低,我们只需要让以上初始化工作在程序生命周期中只执行一次就可以

静态语句块 : 加载阶段执行,最先执行,且只执行一次

静态变量 : 静态变量的值再整个程序生命周期周有效

11. 入口类

项目代码标准化之后,肯定要准备一个程序入口

?

?

?12? 打包

1 普通jar包 : 不能独立运行,一般用于让其他程序引入调用的

2 可执行jar包 : 一般不会被引入

?

?

?

?运行jar包

?

把jar包和地址库放在同一目录下

然后CMD 进入该目录

执行命令 java?? -jar? xxx.jar?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 21:34:12  更:2022-02-14 21:34:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:03:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码