由浅到深认识Java语言(39):网络编程
该文章Github地址:https://github.com/AntonyCheng/java-notes
在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!
上一章:由浅到深认识Java语言(38):I/O流
45.网络编程
软件结构
**C/S结构:**全称为 Client/Server 结构,是指客户端和服务器结构,重点在于客户端开发,常见的程序有QQ,迅雷,百度网盘等软件,但是客户端开发并不适合于 Java ,而适合于 C/C++ ;
**B/S结构:**全称为 Browser/Server 结构,是指浏览器和服务器结构,重点在于服务器端开发,常见浏览器有 IE ,谷歌,火狐等,服务端开发才是适合用 Java 实现的;
两种架构各有优势,但是无论是哪种架构,都离不开网络的支持;
**网络编程:**就是在一定的协议下,实现两台计算机的通信的程序;
网络通信协议
TCP/IP协议参考模型
-
**网络通信协议:**通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
-
TCP/IP协议: 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。

上图中,OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广。
TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能。
- 链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
- 网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。而IP协议是一种非常重要的协议。IP(internet protocal)又称为互联网协议。IP的责任就是把数据从源传送到目的地。它在源地址和目的地址之间传送一种称之为数据包的东西,它还提供对数据大小的重新组装功能,以适应不同网络对包大小的要求。
- 传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。TCP(Transmission Control Protocol)协议,即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。UDP(User Datagram Protocol,用户数据报协议):是一个无连接的传输层协议、提供面向事务的简单不可靠的信息传送服务。
- 应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
而通常我们说的TCP/IP协议,其实是指TCP/IP协议族,因为该协议家族的两个最核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准,所以简称为TCP/IP协议。
TCP与UDP协议
我们所接触较多的是 TCP 协议,而 UDP 协议了解即可;
java.net 包中提供了两种常见的网络协议的支持:
-
UDP:用户数据报协议(User Datagram Protocol);
- 面向无连接的,不可靠的且不安全的协议:UDP 是无连接通信协议,即在传输数据时,数据的发送端和接收端不建立逻辑链接,就是一台计算机向另一台计算机发送数据时不会确认接收端是否存在就会发出信息,同样接收端在收到数据时也不会向发送端反馈是否收到数据,==所以容易产生丢包(数据包丢失)的现象==;
- **消耗资源小,通信效率高:**所以常用于音频,视频和普通数据(QQ,微信消息)的传输,即使丢失一两个数据包也不会对接收结果产生太大影响,但是Java 并不擅长这样的协议;
- **有大小限制:**UDP 协议会把数据限制在 64KB 之内,超出这个范围就不能发送了;
- **数据报(Datagram):**网络传输的基本单位;
-
TCP:传输控制协议(Transmission Control Protocol);
-
**面向连接的,可靠协议:**通信双方必须建立逻辑链接才能传输数据,理论上此种数据传输是可靠无差错的,往往现实不然,它是基于字节流的传输层通信协议,可以连续传输大量的数据,类似于打电话或者是百度云盘的下载;
-
**握手和挥手:**当一台计算机与另一台计算机建立连接时,TCP 协议会采用“三次握手”方式让它们建立一个连接——用于发送和接收数据虚拟链路,当数据传输完毕后 TCP 协议会采用“四次挥手”的方式断开连接;
-
**三次握手:**TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠,但是会浪费网络资源,速度慢;
-
第一次握手:客户端向服务器端发出连接请求,等待服务器确认;
注意:服务器端永远不会向客户端主动发起连接请求;
-
第二次握手:服务器端向客户端送回一个响应,通知客户端收到了连接请求;
-
第三次握手:客户端再次向服务器端发出确认信息,确认连接;
-
-
**四次挥手:**TCP协议中,在发送数据结束后,释放连接时需要经过四次挥手;
-
第一次挥手:客户端向服务器端提出结束连接,让服务器端做最后的准备工作,此时客户端处于半关闭状态,即不再向服务器端发送数据,但是可以接收数据;
-
第二次挥手:服务器端收到释放连接的请求后,会将最后的数据发给客户端,并且告知上层应用进程不再接收数据;
-
第三次挥手:服务器端发送完数据后,会给客户端发送一个释放连接的报文,那么客户端接收后就知道可以正式释放连接了;
-
第四次挥手:客户端接收到服务器端最后的释放连接报文后,要回复一个彻底断开的报文,这样服务器端收到之后才会彻底释放连接;
-
-
-
网络编程三要素
协议
**协议:**计算机网络通信必须遵守的规则,详情请看上节介绍;
IP地址
IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设备做唯一的编号。假如我们把“个人电脑”比作“一台电话”的话,那么“IP地址”就相当于“电话号码”;
IP地址分类方式一:
-
IPv4:是一个32位的二进制数,通常被分为4个字节,表示成
a.b.c.d的形式,例如192.168.65.100。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个; -
IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张;
为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成
ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题;
IP地址分类方式二:
公网地址(万维网使用)和 私有地址(局域网使用)。192.168.开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用;
常用命令:
- 查看本机IP地址,在控制台输入:
ipconfig

- 检查网络是否连通,在控制台输入:
ping 空格 IP地址
ping 192.168.80.1

特殊的IP地址:
- 本地回环地址(hostAddress):
127.0.0.1 - 主机名(hostName):
localhost
域名:
因为IP地址数字不便于记忆,因此出现了域名,域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。 ------- 域名解析;
端口号
网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,那么在网络通信时,如何区分这些进程呢?
如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程(应用程序)了;
- 端口号:用两个字节表示的整数,它的取值范围是0~65535。
- 公认端口:0~1023。被预先定义的服务通信占用,如:HTTP(80),FTP(21),Telnet(23);
- 注册端口:1024~49151。分配给用户进程或应用程序。如:Tomcat(8080),MySQL(3306),Oracle(1521);
- 动态/ 私有端口:49152~65535;
如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败;
利用 协议+IP地址+端口号 三元组合,就可以标识网络中的进程: IP 192.168.1.100:8080 ,那么进程间的通信就可以利用这个标识与其它进程进行交互;
InetAddress类
InetAddress 类获取本机 IP 地址对象;
package top.sharehome.Demo;import java.net.InetAddress;public class Demo {public static void main(String[] args) throws Exception {/*** 以下是该类获取自己计算机的ip地址和主机名*/InetAddress inetAddress = InetAddress.getLocalHost();String ip = inetAddress.getHostAddress();String hostName = inetAddress.getHostName();System.out.println("inetAddress = " + inetAddress);System.out.println("ip = " + ip);System.out.println("hostName = " + hostName);System.out.println("===================================");/*** 以下是该类获取远程计算机的ip地址和主机名*/InetAddress inetAddress1 = InetAddress.getByName("byName");String ip1 = inetAddress1.getHostAddress();String hostName1 = inetAddress1.getHostName();System.out.println("inetAddress1 = " + inetAddress1);System.out.println("ip1 = " + ip1);System.out.println("hostName1 = " + hostName1);}
}
打印效果如下:

报错是因为这个远程计算机的主机名是不存在的!
TCP:Socket和ServerSocket
通信的两端都要有Socket(也可以叫“套接字”),是两台机器间通信的端点。网络通信其实就是Socket间的通信。Socket可以分为:
- 流套接字(stream socket):使用TCP提供可依赖的字节流服务
- ServerSocket:此类实现TCP服务器套接字。服务器套接字等待请求通过网络传入。
- Socket:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
- 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务
- DatagramSocket:此类表示用来发送和接收UDP数据报包的套接字。
图示如下:

图示示例如下:
服务器端:
package top.sharehome.Demo;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;/*** 下面实现了一个服务器端*/
public class ICPServer {public static void main(String[] args) {ServerSocket serverSocket = null;InputStream inputStream = null;OutputStream outputStream = null;try {//使用serverSocket建立服务器端,并设置端口serverSocket = new ServerSocket(8888);//使用serverSocket类中的accept()方法获取接收端,即客户端的对象Socket accept = serverSocket.accept();//使用accept.getInputStream()方法创建输入流并从客户端获取内容inputStream = accept.getInputStream();byte[] arr = new byte[1024];int flag = inputStream.read(arr);System.out.println(new String(arr, 0, flag));System.out.println("accept = " + accept);//accept.getOutputStream()方法撞见一个输出流并向客户端输出内容outputStream = accept.getOutputStream();outputStream.write("thank".getBytes());} catch (IOException e) {e.printStackTrace();} finally {try {if (serverSocket != null) {serverSocket.close();}} catch (IOException e) {e.printStackTrace();}try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {e.printStackTrace();}try {if (outputStream != null) {outputStream.close();}} catch (IOException e) {e.printStackTrace();}}}
}
客户端:
package top.sharehome.Demo;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;/*** 下面实现了一个客户端*/
public class ICPclient {public static void main(String[] args) {Socket socket = null;OutputStream outputStream = null;InputStream inputStream = null;try {//使用Socket建立客户端,并指定ip地址和端口socket = new Socket("127.0.0.1", 8888);//调用socket.getOutputStream()方法获取输出流并向服务器端输出内容outputStream = socket.getOutputStream();outputStream.write("Hello".getBytes());//调用socket.getInputStream()方法获取输入流并从服务器端输入内容inputStream = socket.getInputStream();byte[] arr = new byte[1024];int flag = inputStream.read(arr);System.out.println(new String(arr, 0, flag));System.out.println("socket = " + socket);} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}try {if (outputStream != null) {outputStream.close();}} catch (IOException e) {e.printStackTrace();}try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {e.printStackTrace();}}}
}
打印效果如下:


上传服务器死循环问题
在 I/O 流的学习中,我们结识到了通过循环来快速写入和读取的方法,但是这个循环放在客户端和服务器端之间就会出现很严重的问题,以 客户端通过基础流读取客户端文件数据然后向服务器写入数据,服务器端读取客户端数据后再通过基础流向服务器端文件里 为例:
//客户端相关操作代码:
byte[] bytes = new byte[1024];
int flag = 0;
while ((flag = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, flag);
}
inputStream = socket.getInputStream();
flag = inputStream.read(bytes);
//服务器端相关操作代码:
byte[] bytes = new byte[1024];
int flag = 0;
while ((flag = inputStream.read(bytes)) != -1) {fileOutputStream.write(bytes, 0, flag);
}
当客户端读取数据到客户端文件末尾处时会返回 -1,然后结束掉客户端的循环,但是由于 read() 方法的阻塞性,服务器端中的 read() 方法会一直等待着客户端继续写入数据,但是此时的客户端并不会再向服务器端传输数据,所以导致了服务器没办法完成该次相应,从而使客户端中的 read() 也进入了阻塞状态,进而进入一种双终端之间的死循环;
解决办法:
再写入完毕之后使用 Socket 类中的 shutdownOutput() 方法手动关闭写入通道,并且告诉对方自己已经写入完毕;
//客户端相关操作代码:
byte[] bytes = new byte[1024];
int flag = 0;
while ((flag = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, flag);
}
socket.shutdownOutput(); //手动关闭写入通道
inputStream = socket.getInputStream();
flag = inputStream.read(bytes);
//服务器端相关操作代码:
byte[] bytes = new byte[1024];
int flag = 0;
while ((flag = inputStream.read(bytes)) != -1) {fileOutputStream.write(bytes, 0, flag);
}
文件名重复问题
向服务器上传内容就类似于复制粘贴,如果粘贴时的文件名和粘贴路径中的文件有所重复,那么原来的文件就会被覆盖掉,这样的话向服务器上传文件始终只能是一个文件,所以我们要自定义一些文件名,最常见的就是 System.currentTimeMillis() 获取得到毫秒值再加上是 new Random().nextInt() 随机数;
示例如下:
//客户端相关代码:
fileInputStream = new FileInputStream("d:\\大学课程学习文档\\java\\Practice\\ImgClient\\1.jpg"); //由客户端读取客户端文件;
//服务器端相关代码:
fileOutputStream = new FileOutputStream("d:\\大学课程学习文档\\java\\Practice\\ImgServer\\" + System.currentTimeMillis() + new Random().nextInt(999999999) +".jpg"); //由服务器端接收客户端的数据并且将数据打包重命名为System.currentTimeMillis() + new Random().nextInt(999999999).jpg
图片上传案例
示例图片如下:

客户端代码:
package top.sharehome.Demo;import java.io.*;
import java.net.Socket;public class ICPclient {public static void main(String[] args) {/*** 我们需要创建四个流* 1.连接服务器* 2.字节流将图片引入* 3.链接对象的字节输出流,将图片写入服务器* 4.读取服务器返回的上传成功的消息*/FileInputStream fileInputStream = null;OutputStream outputStream = null;Socket socket = null;InputStream inputStream = null;try {socket = new Socket("127.0.0.1", 8888);fileInputStream = new FileInputStream("d:\\大学课程学习文档\\java\\Practice\\ImgClient\\1.jpg");outputStream = socket.getOutputStream();byte[] bytes = new byte[1024];int flag = 0;while ((flag = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, flag);}socket.shutdownOutput();inputStream = socket.getInputStream();flag = inputStream.read(bytes);System.out.println("socket = " + socket);System.out.println(new String(bytes, 0, flag));} catch (IOException e) {e.printStackTrace();} finally {try {if (fileInputStream != null) {fileInputStream.close();}} catch (IOException e) {e.printStackTrace();}try {if (socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}}
}
服务器端代码:
package top.sharehome.Demo;import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;public class ICPServer {public static void main(String[] args) {/*** 我们需要建立三个流* 1.和客户端建立连接* 2.接收客户端传来的数据* 3.返回上传成功的信息*/ServerSocket serverSocket = null;FileOutputStream fileOutputStream = null;InputStream inputStream = null;OutputStream outputStream = null;Socket client = null;try {serverSocket = new ServerSocket(8888);client = serverSocket.accept();fileOutputStream = new FileOutputStream("d:\\大学课程学习文档\\java\\Practice\\ImgServer\\" + System.currentTimeMillis() + new Random().nextInt(999999999) +".jpg");inputStream = client.getInputStream();byte[] bytes = new byte[1024];int flag = 0;while ((flag = inputStream.read(bytes)) != -1) {fileOutputStream.write(bytes, 0, flag);}System.out.println("client = " + client);outputStream = client.getOutputStream();outputStream.write("上传图片成功!".getBytes());} catch (IOException e) {e.printStackTrace();} finally {try {if (serverSocket != null) {serverSocket.close();}} catch (IOException e) {e.printStackTrace();}try {if (fileOutputStream != null) {fileOutputStream.close();}} catch (IOException e) {e.printStackTrace();}try {if (client != null) {client.close();}} catch (IOException e) {e.printStackTrace();}}}
}
打印效果如下:


UDP:DatagramSocket
基于UDP协议的网络编程仍然需要在通信实例的两端各建立一个Socket,但这两个Socket之间并没有虚拟链路,这两个Socket只是发送、接收数据报的对象,Java提供了DatagramSocket对象作为基于UDP协议的Socket,使用DatagramPacket代表DatagramSocket发送、接收的数据报;
DatagramSocket 类的常用方法:
- public DatagramSocket(int port)创建数据报套接字并将其绑定到本地主机上的指定端口。套接字将被绑定到通配符地址,IP 地址由内核来选择;
- public DatagramSocket(int port,InetAddress laddr)创建数据报套接字,将其绑定到指定的本地地址。本地端口必须在 0 到 65535 之间(包括两者)。如果 IP 地址为 0.0.0.0,套接字将被绑定到通配符地址,IP 地址由内核选择;
- public void close()关闭此数据报套接字;
- public void send(DatagramPacket p)从此套接字发送数据报包。DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号;
- public void receive(DatagramPacket p)从此套接字接收数据报包。当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。数据报包也包含发送方的 IP 地址和发送方机器上的端口号。 此方法在接收到数据报前一直阻塞。数据报包对象的 length 字段包含所接收信息的长度。如果信息比包的长度长,该信息将被截短;
DatagramPacket类的常用方法:
- public DatagramPacket(byte[] buf,int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。 length 参数必须小于等于 buf.length;
- public DatagramPacket(byte[] buf,int length,InetAddress address,int port)构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。length 参数必须小于等于 buf.length;
- public int getLength()返回将要发送或接收到的数据的长度;
示例代码
发送端:
package top.sharehome.Demo;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;public class Send {public static void main(String[] args)throws Exception {
// 1、建立发送端的DatagramSocketDatagramSocket ds = new DatagramSocket();//要发送的数据ArrayList<String> all = new ArrayList<String>();all.add("hello java");all.add("hello C");all.add("hello php");all.add("hello python");//接收方的IP地址InetAddress ip = InetAddress.getByName("127.0.0.1");//接收方的监听端口号int port = 9999;//发送多个数据报for (int i = 0; i < all.size(); i++) {
// 2、建立数据包DatagramPacketbyte[] data = all.get(i).getBytes();DatagramPacket dp = new DatagramPacket(data, data.length, ip, port);
// 3、调用Socket的发送方法ds.send(dp);}// 4、关闭Socketds.close();}
}
接收端:
package top.sharehome.Demo;import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Receive {public static void main(String[] args) throws Exception {
// 1、建立接收端的DatagramSocket,需要指定本端的监听端口号DatagramSocket ds = new DatagramSocket(9999);//一直监听数据while(true){// 2、建立数据包DatagramPacketbyte[] buffer = new byte[1024*64];DatagramPacket dp = new DatagramPacket(buffer , buffer.length);// 3、调用Socket的接收方法ds.receive(dp);//4、拆封数据String str = new String(buffer,0,dp.getLength());System.out.println(str);}}
}
下一章:由浅到深认识Java语言(40):枚举
相关文章:
由浅到深认识Java语言(39):网络编程
该文章Github地址:https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.c…...
PCL 彩色点云RGB转灰度并显示
目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、原理概述 不同要素之间的灰度差异较为明显。点云灰度值与RGB属性的关系为:...
RHEL9部署Docker环境
华子目录 Docker引擎架构docker引擎架构示意图执行过程示例 RHEL9上安装Docker1.系统要求2.安装yum-utils工具包3.yum安装docker-ce4.配置docker镜像加速docker拉取镜像的过程配置阿里云镜像仓库重新加载守护进程重启Docker服务 5.拉取并运行hello-world镜像6.测试是否安装成功…...
Vue3.0云里雾里
目录:一篇通识Vue3.0 1.OptionsAPI(选项式)和CompositionAPI(组合式) 2.setup setup语法糖 ref响应式数据 reactive只能定义对象类型的响应式数据(用情专一) toRefs解构 计算属性computed watch侦听 WatchEffect 标签的Ref属性 组件上的ref就是获取组件实例…...
idea类已经存在却报错
一句话导读 在idea中导入新的项目,很多类都飘红报错,mvn compile可以通过,可能是因为idea缓存问题导致。 由于这个项目是由老项目复制过来后,再继续开发新的功能,很多同事导入后,都爆出新的类找不到。而编译…...
MySQL---视图
目录 一、介绍 二、语法 三、视图的更新 四、视图作用 一、介绍 视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。 通俗的讲&#…...
策略路由-IP-Link-路由协议简介
策略路由 策略路由和路由策略的不同 1.策略路由的操作对象是数据包,在路由表已经产生的情况下,不按照路由表进行转发,而是根据需要,依照某种策略改变数据包的转发路径 2.路由策略的操作对象是路由信息。路由策略的主要实现了路…...
数位五五(Java)
数位五五 题目描述 求出[a,b]区间内有多少个数数位之和为 55 的倍数。 输入格式 输入一行包含两个整数a ,b。 输出格式 输出一个整数。 样例输入输出 样例输入 10 20样例输出 2数据范围 对于 100% 的数据,保证 1≤a≤b≤1000000。 样例解释 …...
蓝桥杯G431RBT6——定时器中使用led冲突以及led与lcd冲突等一系列问题
本文是解决 同时在 定时器中点灯 与 LCD屏幕显示 冲突异常的问题 我们大家都知道,G431RBT6开发板上led与lcd是冲突的,所以在lcd.c文件中的这三个函数中 void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue) void LCD_WriteRAM_Prepare(void) void LCD_Wr…...
物联网(IoT)常用的通信协议
物联网(IoT)的通信协议是物联网设备之间交换数据的规则和标准。这些协议对于确保设备能够有效、安全地通信至关重要。下面是物联网通信协议的概述: 1. MQTT(消息队列遥测传输) 概述:MQTT是一种轻量级的发…...
关于C/C++,Linux/MacOS/Windows 平台虚拟内存分配
在 Windows 平台上面建议通过 VirtualAlloca、VirtualAllocaEx 核心库函数来分配虚拟内存,而不是通过 MMF(Memory Mapping File / 内存映射文件)技术来载入虚拟内存。 这是因为,在 Windows 平台上面,通过MMF技术分配的…...
如何在服务器上传/下载文件
从服务器下载文件到本地 打开xshell,输入:ssh root159.xxx.xxx.xx 然后需要输入密码 cd到目录文件夹下 cd /enmotech apt install zip zip -r uploads.zip uploads apt install lrzsz sz uploads.zip 从本地上传文件到服务器 如果文件是放在E盘…...
C++ 之多态虚函数原理及应用
文章目录 多态基本概念和原理虚函数的基本原理和概念虚析构和纯虚析构多重继承中的虚函数小结 多态基本概念和原理 多态的基本概念 **多态是C面向对象三大特性之一** 多态的定义 多态是一种面向对象编程概念,指同一个行为(方法)在不同的对象上…...
亮数据——让你的IP走出去,让价值返回来
亮数据——让你的IP走出去,让价值返回来 前言跨境电商最最最大的痛点——让IP走出去超级代理服务器加速网络免费的代理管理软件亮数据解决痛点亮数据优势介绍亮数据浏览器的使用示例总结 前言 当前社会信息的价值是不可想象的,今天在亮数据中看到了个【…...
spring boot-引入Redis并封装redistemplate操作工具类
文章目录 一、关于spring-redis二、springboot引入Redis及其使用案例三、封装redistemplate操作工具类 一、关于spring-redis spring-data-redis针对jedis提供了如下功能: 连接池自动管理,提供了一个高度封装的“RedisTemplate”类 针对jedis客户端中大…...
android 11 SystemUI 状态栏打开之后的界面层级关系说明之一
比如WiFi 图标的父layout为: Class Name: ButtonRelativeLayout Class Name: QSTileView Class Name: TilePage Class Name: PagedTileLayout Class Name: QSPanel Class Name: NonInterceptingScrollView Class Name: QSContainerImpl Class Name: FrameLayout Cl…...
C#___锁(lock)
lock是一种语言级别的关键字,用于实现线程同步和互斥。它提供了一种简单的方式来确保多个线程不会同时访问共享资源,从而避免竞争条件和数据不一致的问题。 作用: 1、避免并行运算中,共享数据的的读写安全问题; 2、并…...
JAVA的sort用法详解(二维数组排序,List<>排序,lambada表达式,自定义类型排序)
目录 前言: 一维数组降序: 方法1.Comparator接口: 代码实现: 方法2.Collections.reverseOrder(): 代码实现: 二维数组排序: 代码如下: List<>排序: 代码…...
数据分析能力模型分析与展示
具体内容: 专业素质 专业素质-01 数据处理 能力定义•能通过各种数据处理工具及数据处理方法,对内外部海量数据进行清洗和运用,提供统一数据标准,为业务分析做好数据支持工作。 L1•掌握一…...
BUG未解之谜01-指针引用之谜
在leetcode里面刷题出现的问题,当我在sortedArrayToBST里面给root赋予初始值NULL之后,问题得到解决! 理论上root是未初始化的变量,然后我进入insert函数之后,root引用的内容也是未知值,因此无法给原来的二叉…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
