【JAVA基础之网络编程】UDP和TCP协议以及三次握手和四次挥手的过程
🔥作者主页:小林同学的学习笔录
🔥mysql专栏:小林同学的专栏
目录
1. 网络编程
1.1 概述
1.2 网络编程的三要素
1.2.1 IP地址
1.2.2 InetAddress
1.2.3 端口和协议
1.3 UDP协议
1.3.1 UDP发送数据
1.3.2 UDP接收数据
1.4 TCP协议
1.4.1 TCP协议实例
1.4.2 三次握手,四次挥手
1. 网络编程
1.1 概述
概述:在网络通信协议下,不同计算机上运行的程序,进行数据的传输
java.net包中可以看见常见的网络应用程序API
常见的软件架构:
C/S:Client / Server 客户端 / 服务器
- 需要用户下载并安装客户端程序,在远程有一个服务器程序
 - 优缺点: 
- 画面可以做的比较精美,用户体验好(不需要网络传输,数据来源于安装包)
 - 需要开发客户端,也需要开发服务端
 - 用户需要下载和更新的时候太麻烦
 
 
B/S:Browser / Server 浏览器 / 服务器
- 只需要一个浏览器,通过访问不同的网址实现操作程序,客户访问不同的服务器
 - 优缺点: 
- 不需要开发客户端,只需要页面 + 服务器
 - 用户不需要下载,打开浏览器就能使用
 - 如果应用过大,用户体验将受到影响(因为数据进行网络传输效率比较低)
 
 
1.2 网络编程的三要素
IP:设备在网络中的地址,是唯一标识
端口号:应用程序在设备中的唯一标识
协议:数据在网络中的传输规则,常见的协议有UDP,TCP,HTTP,HTTPS,FTP

1.2.1 IP地址
IP地址分为两大类:
-  
IPv4:是给每个连接在网络上的主机分配一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节。例如一个采用二进制形式的IP地址是“11000000 10101000 00000001 01000010”,这么长的地址,处理起来也太费劲了。为了方便使用,IP地址经常被写成十进制的形式,中间使用符号“.”分隔不同的字节。于是,上面的IP地址可以表示为“192.168.1.66”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多,最多有2^32次方个IP
 -  
IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,每一组用分号隔开,这样就解决了网络地址资源数量不够的问题,最多有2^128次方个IP、
 
DOS常用命令:
-  
ipconfig:查看本机IP地址
 -  
ping IP地址:检查网络与目标主机是否能连通
 
特殊IP地址:
-  
127.0.0.1:是回送地址,可以代表本机地址LocalHost,一般用来测试使用
 
疑问:假设192.168.1.100是我的电脑IP,那么这个IP跟127.0.0.1是一样吗?
不一样,192.168.1.100和127.0.0.1不是一样的IP地址。192.168.1.100是局域网内的私有IP地址,用于在局域网中标识设备。而127.0.0.1是本地回环地址,用于在同一台设备内部进行通信。当你的计算机尝试连接127.0.0.1时,它实际上是在尝试与自己通信,而不是与网络上的其他设备通信。
疑问:公网地址(万维网使用)和私有地址(局域网使用)的区别?
公网地址和私有地址之间的主要区别在于它们的可访问性和范围。公网地址是全球唯一的IP地址,用于在互联网上唯一标识设备和进行通信。私有地址则是在局域网内使用的地址,不会在互联网上进行路由,因此不能直接从互联网上访问。私有地址用于在局域网内部进行通信,而通过路由器进行网络地址转换(NAT),可以允许多个设备共享单个公网IP地址来访问互联网。
1.2.2 InetAddress
InetAddress 是 Java 编程语言中用于表示 IP 地址的类。它提供了一种将 IP 地址和主机名相互转换的方式。通过 InetAddress 类,可以实现网络通信中的主机名解析、IP 地址解析等功能。
成员方法:

1.2.3 端口和协议
-  
端口
-  
设备上应用程序的唯一标识
 
 -  
 -  
端口号
-  
用两个字节表示的整数,它的取值范围是0~65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败
 
 -  
 -  
协议
-  
计算机网络中,连接和通信的规则被称为网络通信协议
 
 -  
 -  
UDP协议
-  
用户数据报协议(User Datagram Protocol)
 -  
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
 -  
由于使用UDP协议消耗系统资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输
 -  
速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
 -  
例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议
 
 -  
 -  
TCP协议
-  
传输控制协议 (Transmission Control Protocol)
 -  
TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”
 -  
速度慢,没有大小限制,数据安全
 -  
三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
第一次握手,客户端向服务器端发出连接请求,等待服务器确认
第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
第三次握手,客户端再次向服务器端发送确认信息,确认连接
 -  
完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等
 
 -  
 
1.3 UDP协议
1.3.1 UDP发送数据
构造方法:

成员方法:

发送数据的步骤
-  
创建发送端的Socket对象(DatagramSocket)
 -  
创建数据,并把数据打包(DatagramPacket)
 -  
调用DatagramSocket对象的方法发送数据(send)
 -  
关闭发送端
 
代码演示:
public class Send {public static void main(String[] args) throws IOException {/*** 创建发送端的Socket对象(DatagramSocket)* 创建数据,并把数据打包(DatagramPacket)* 调用DatagramSocket对象的方法发送数据(send)* 关闭发送端*///这里参数如果没有端口号,系统会自动分配一个端口号DatagramSocket socket = new DatagramSocket(10000);String str = "龙颜大怒666";byte[] bytes = new byte[1024];bytes = str.getBytes();DatagramPacket packet = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("127.0.0.1"),10086);socket.send(packet);socket.close();}
} 
 
 
 
 
1.3.2 UDP接收数据
构造方法:

成员方法:

接收数据的步骤
-  
创建接收端的Socket对象(DatagramSocket)
 -  
创建一个数据包,用于接收数据(DatagramPacket)
 -  
调用DatagramSocket对象的方法接收数据(receive)
 -  
解析数据包,并把数据在控制台显示
 -  
关闭接收端
 
代码演示:
public class Receive {public static void main(String[] args) throws IOException {/*** 创建接收端的Socket对象(DatagramSocket)* 创建一个数据包,用于接收数据(DatagramPacket)* 调用DatagramSocket对象的方法接收数据(receive)* 解析数据包,并把数据在控制台显示* 关闭接收端*///注意:这里的端口号一定要与发送端中的数据包端口一致,不然会收不到数据DatagramSocket socket = new DatagramSocket(10086);byte[] bytes = new byte[1024];DatagramPacket packet = new DatagramPacket(bytes,bytes.length);//这个方法会一直等待发送端发送信息过来,直到拿到数据才会取消阻塞socket.receive(packet);byte[] data = packet.getData();InetAddress address = packet.getAddress();int port = packet.getPort();System.out.println("数据:" + new String(data,0,packet.getLength()) + " 主机IP:" + address + " 端口号:" + port);socket.close();}
}输出结果:数据:龙颜大怒666 主机IP:/127.0.0.1 端口号:10000 
 
 
1.4 TCP协议
1.4.1 TCP协议实例

代码演示:
public class Client {public static void main(String[] args) throws IOException {//创建socket对象//细节:在创建对象同时会连接服务端//如果连接不上代码会报错Socket socket = new Socket("127.0.0.1",10000);//创建socket的输出流通道OutputStream outputStream = socket.getOutputStream();//写入数据outputStream.write("你好呀".getBytes());//关闭资源socket.close();outputStream.close();}
}
 
public class Server {public static void main(String[] args) throws IOException {//这里的端口号要跟客户端的Socket保持一致ServerSocket serverSocket = new ServerSocket(10000);//这里会阻塞等待客户端发送信息Socket socKet = serverSocket.accept();//通过socket获取输入流通道InputStream inputStream = socKet.getInputStream();//解决中文乱码问题InputStreamReader inputStreamReader = new InputStreamReader(inputStream);BufferedReader bufferedReader = new BufferedReader(inputStreamReader);int len;while ((len = bufferedReader.read()) != -1) {System.out.print((char) len);}//关闭资源serverSocket.close();socKet.close();}
} 
 
 
1.4.2 三次握手,四次挥手

三次握手:为了确保连接的建立

四次挥手:确保连接断开,且数据处理完毕

1.5 综合练习
1.5.1 多发多送
public class Test01 {public static void main(String[] args) throws IOException {/*** 客户端:多次发送数据* 服务端:接收多次数据,并打印*/Socket socket = new Socket("127.0.0.1",10002);OutputStream outputStream = socket.getOutputStream();Scanner scanner = new Scanner(System.in);while (true) {System.out.println("请输入你要发送的信息:");String str = scanner.nextLine();//用户输入886表示退出if("886".equals(str)){break;}outputStream.write(str.getBytes());}//关闭资源outputStream.close();socket.close();}
}public class TestServer01 {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(10002);Socket socket = serverSocket.accept();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));int len;while((len = bufferedReader.read()) != -1){System.out.print((char)len);}//关闭资源socket.close();serverSocket.close();}
} 
 
1.5.2 接收并反馈
public class Test02 {public static void main(String[] args) throws IOException {/*** 客户端:发送一条数据,接收服务端反馈的消息并打印* 服务端:接收数据并打印,再给客户端反馈信息*/Socket socket = new Socket(InetAddress.getLocalHost(),10003);Scanner scanner = new Scanner(System.in);OutputStream os = socket.getOutputStream();System.out.println("请输入要发给服务端的信息:");String str = scanner.nextLine();os.write(str.getBytes());//细节:这里需要一个结束标记,服务端那边读取才知道结束socket.shutdownOutput();InputStreamReader isr = new InputStreamReader(socket.getInputStream());int len;while ((len = isr.read()) != -1){System.out.print((char)len);}socket.close();}
}public class TestServer02 {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(10003);Socket socket = serverSocket.accept();InputStreamReader isr = new InputStreamReader(socket.getInputStream());int len;//细节://read方法从连接通道读取数据//但是需要一个结束标记循环才会停止//否则,程序就会一直停在read方法这里,等待读取下面的数据while ((len = isr.read()) != -1){System.out.print((char)len);}OutputStream os = socket.getOutputStream();os.write("收到客户端的信息".getBytes());socket.close();serverSocket.close();}
} 
 
1.5.3 上传练习
public class Test03 {public static void main(String[] args) throws IOException {/*** 案例需求:* 客户端:数据来自于本地文件,接收服务器反馈* 服务器:接收到的数据写入本地文件,给出反馈*/Socket socket = new Socket("127.0.0.1", 10000);byte[] bytes = new byte[1024];int len;//这种方式效率比较低//FileInputStream fis = new FileInputStream("D:\\img\\0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg");//OutputStream os = socket.getOutputStream();//缓存流可以降低磁盘IO次数BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source/0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg"));BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//发送数据while ((len = bis.read(bytes)) != -1){bos.write(bytes,0,len);}//设置结束标记socket.shutdownOutput();//接收数据InputStreamReader isr = new InputStreamReader(socket.getInputStream());while ((len = isr.read()) != -1){System.out.print((char)len);}socket.close();}
}public class TestServer03 {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(10000);Socket socket = serverSocket.accept();InputStream is = socket.getInputStream();byte[] bytes = new byte[1024];int len;//效率低//FileOutputStream fos = new FileOutputStream(new File("D:\\test\\a.jpg"));//这里需要解决文件名重复问题,导致原先的文件会被后面的覆盖,用UUID来解决//System.out.println(UUID.randomUUID());//72e165ae-98ad-4cd4-80e9-c9f86b910461,我们一般看到的效果是没有"-"的,需要处理一下String name = UUID.randomUUID().toString().replace("-", "");//BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\a.jpg"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\" + name + ".jpg"));//边读边写while((len = is.read(bytes)) != -1){bos.write(bytes,0,len);}//发送数据OutputStream os = socket.getOutputStream();os.write("收到数据啦".getBytes());socket.close();serverSocket.close();}
} 
 
 
1.5.4 服务器改写成多线程,以及线程优化
服务器只能处理一个客户端请求,接收完一个图片之后,服务器就关闭了。
优化方案一:使用循环
弊端:第一个用户正在上传数据,第二个用户就来访问了,此时第二个用户是无法成功上传的。
所以,使用多线程改进
优化方案二:使用循环 + 多线程
每来一个用户,就开启多线程处理
public class Test04 {public static void main(String[] args) throws IOException {/*** 案例需求:* 客户端:数据来自于本地文件,接收服务器反馈* 服务器:接收到的数据写入本地文件,给出反馈*/Socket socket = new Socket("127.0.0.1", 10000);byte[] bytes = new byte[1024];int len;//这种方式效率比较低//FileInputStream fis = new FileInputStream("D:\\img\\0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg");//OutputStream os = socket.getOutputStream();//缓存流可以降低磁盘IO次数BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source/0a3b3288-3446-4420-bbff-f263d0c02d8e.jpg"));BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//发送数据while ((len = bis.read(bytes)) != -1){bos.write(bytes,0,len);}//设置结束标记socket.shutdownOutput();//接收数据InputStreamReader isr = new InputStreamReader(socket.getInputStream());while ((len = isr.read()) != -1){System.out.print((char)len);}socket.close();}
}public class TestServer04 {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(10000);ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,//核心线程数量16,//线程池总大小60,//空闲时间TimeUnit.SECONDS,//空闲时间(单位)new ArrayBlockingQueue<>(2),//队列Executors.defaultThreadFactory(),//线程工厂,让线程池如何创建线程对象new ThreadPoolExecutor.AbortPolicy()//阻塞队列);while (true) {//等待客户端连接Socket socket = serverSocket.accept();//一个用户对应一条线程//new Thread(new MyRunnable(socket)).start();//线程池进行优化poolExecutor.submit(new MyRunnable(socket));}}
}public class MyRunnable implements Runnable {private Socket socket;public MyRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {InputStream is = socket.getInputStream();byte[] bytes = new byte[1024];int len;//效率低//FileOutputStream fos = new FileOutputStream(new File("D:\\test\\a.jpg"));//这里需要解决文件名重复问题,导致原先的文件会被后面的覆盖,用UUID来解决//System.out.println(UUID.randomUUID());//72e165ae-98ad-4cd4-80e9-c9f86b910461,我们一般看到的效果是没有"-"的,需要处理一下String name = UUID.randomUUID().toString().replace("-", "");//BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\a.jpg"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("img\\" + name + ".jpg"));//边读边写while ((len = is.read(bytes)) != -1) {bos.write(bytes, 0, len);}//发送数据OutputStream os = socket.getOutputStream();os.write("上传成功".getBytes());} catch (IOException e) {throw new RuntimeException(e);} finally {if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}} 
相关文章:
【JAVA基础之网络编程】UDP和TCP协议以及三次握手和四次挥手的过程
🔥作者主页:小林同学的学习笔录 🔥mysql专栏:小林同学的专栏 目录 1. 网络编程 1.1 概述 1.2 网络编程的三要素 1.2.1 IP地址 1.2.2 InetAddress 1.2.3 端口和协议 1.3 UDP协议 1.3.1 UDP发送数据 1.3.2 UDP接收数据 1.4…...
基于python+Django大数据的电影市场预测分析系统设计与实现
博主介绍: 大家好,本人精通Java、Python、C#、C、C编程语言,同时也熟练掌握微信小程序、Php和Android等技术,能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验,能够为学生提供各类…...
消息传递与集成:使用Springboot进行异步通信
消息传递与集成:使用Spring Boot进行异步通信 在现代的分布式系统中,异步通信已经成为了一种常见的设计模式。通过使用消息队列和事件驱动架构,我们可以实现系统之间的解耦,提高系统的可扩展性和可靠性。本文将介绍如何使用Sprin…...
【论文速读】Transformer:Attention Is All You Need
Transformer:Attention Is All You Need 摘要模型架构注意力模型Scaled Dot-ProductMulti-Head Attention Position-wise Feed-Forward NetworksEmbeddings and SoftmaxPositional Encoding 摘要 我们提出了一种新的简单的网络架构,Transformer…...
小短片创作-组装场景(一)
1、项目基础设置 通过第三人称模板,创建1个项目 1.自动曝光:关闭,因为要做专业的小短片,曝光需要手动控制。 2.扩展自动曝光中的默认亮度范围:启用 3.全局光照系统:选择屏幕空间光照(SSGI&am…...
二元关系表示
一、二元关系的定义和表示 什么是二元关系?对集合A和B,A\timesB的任意子集R为A到B的一个二元关系。当AB时,A\timesA的任一子集R称为A上的一个二元关系。在不引起误解的情况下,二元关系可简称关系。 若|A|m,|B|n,则A到…...
Android Audio基础——AudioFlinger音频流管理(八)
从前面 AudioTrack、PlaybackThread、输出流设备三者的关系中,我们看到 AudioTrack 把音频流数据送入到对应的 PlaybackThread 中,那么应用进程是如何控制音频流的开始播放 start()、停止播放 stop()、暂停播放 pause()。这一章节我们就来继续分析。 一、音频流管理 应用进程…...
二进制部署k8s集群 部署高可用master节点
目录 本次部署的环境 一、master02 节点部署 二、负载均衡部署 安装nginx服务 部署keepalive服务 修改node节点上的配置文件 在master节点上创建pod 三、部署 Dashboard 二进制部署k8s集群部署的步骤总结 (1)k8s的数据存储中中心的搭建 etcd &…...
linux创建私有docker仓库以及推拉
创建私有仓库: 1.下载 registry镜像。 2.执行 registry 镜像(#为注释内容,\为换行): docker run -d \# --restartalways每次都是开机自动启动--restartalways \# --name registry 表示容器名--name registry \# 表示…...
如何将照片从 iPhone 传输到闪存驱动器【无质量损坏】
概括 人们喜欢用 iPhone 拍照,因为照片通常都很漂亮,这都要归功于 iPhone 令人惊叹的技术。但照片更新后会占用更多空间,并且您可能会开始收到没有存储空间的通知。因此,您可以将照片传输到 USB 驱动器,然后从 iPhone…...
【MySQL精通之路】InnoDB(7)-锁和事务模型(2)-事务模型
主博客: 【MySQL精通之路】InnoDB(7)-锁和事务模型-CSDN博客 上一篇: 【MySQL精通之路】InnoDB(7)-锁和事务模型(1)-锁-CSDN博客 下一篇: 目录 1.事务隔离级别 2.1 可重复读 2.2 读已提交 2.3 读取未提交 2.4 序列化读 2.自动提交、…...
python中的可哈希和不可哈希
python 中的每一个对象都有一个哈希值,哈希值是一个固定长度的整数,它通常用于快速比较对象的相等性。 如果在对象的生命周期里该对象的哈希值从未改变,那么这个对象是可哈希的(hashable),也称为不可变的。…...
docker命令详解大全
Docker是一种流行的容器化平台,用于快速部署应用程序并管理容器的生命周期。以下是一些常用的Docker命令及其用途的概述: docker run:创建一个新容器并运行一个命令。docker ps:列出当前运行的容器。docker stop:停止…...
体检系统商业源码,C/S架构的医院体检系统源码,大型健康体检中心管理系统源码
体检系统商业源码,C/S架构的医院体检系统源码,大型健康体检中心管理系统源码 体检信息管理系统软件是对医院体检中心进行系统化和规范化的管理。系统从检前,检中,检后整个业务流程提供标准化以及精细化的解决方案。实现体检业务市…...
Vue CLI 的服务介绍与使用(2024-05-20)
1、介绍 Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供: 通过 vue/cli 实现的交互式的项目脚手架。 通过 vue/cli vue/cli-service-global 实现的零配置原型开发。 一个运行时依赖 (vue/cli-service),该依赖: 可升级…...
java连接ldap实现查询
文章目录 一、项目背景二、准备工作三、验证结果四、易错点讲解易错点1:java: 无法访问org.springframework.ldap.core.LdapTemplate易错点2:java: 无法访问org.springframework.context.ConfigurableApplicationContext易错点3:[LDAP: error…...
openjudge_2.5基本算法之搜索_2990:符号三角形
题目 2990:符号三角形 总时间限制: 1000ms 内存限制: 65536kB 描述 符号三角形的第1行有n个由“”和”-“组成的符号 ,以后每行符号比上行少1个,2个同号下面是”“,2个异号下面是”-“ 。计算有多少个不同的符号三角形,使其所含”…...
springboot错误
错误总结 1、使用IDEA 的 initialalzer显示2、IDEA 新建文件 没有 java class3、java: 错误: 不支持发行版本 22解决方法4、IDEA-SpringBoot项目yml配置文件不自动提示解决办法 1、使用IDEA 的 initialalzer显示 IDEA创建SpringBoot项目时出现:Initialization fail…...
linux的用户管理
新建用户:1.useradd 2.passwd 完成的操作: (1)/etc/passwd添加一行 (2)/etc/shadow添加一行 (3)/etc/group添加一行 (4)创建用户家目录 (5)创建用户邮件文件 例:创建用户jerry,要求: uid:777&am…...
数美滑块研究
周一,在清晨的阳光照耀下,逆向山脚下的小镇宁静而安详。居民们忙碌地开始一天的生活,而在爬虫镇子的边缘,一座古朴的道观显得格外神秘。 阿羊正静静地坐在青石长凳上,摸鱼养神。突然,一道清脆的声音在他耳…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
