从入门到精通:网络基础详解
前言
在现代社会,网络技术已经成为我们日常生活和工作中不可或缺的一部分。从简单的网页浏览到复杂的分布式系统,网络技术都扮演着至关重要的角色。通过这篇文章,读者将从入门到精通,全面掌握网络编程的理论和实践。
重点摘要
网络编程是一个复杂且多样的领域,本节将重点关注以下几个方面:
- 理解应用层的作用,初识HTTP协议:应用层是网络协议栈的顶层,它负责处理特定的应用程序数据。
- 理解传输层的作用,深入理解TCP的各项特性和机制:传输层在网络协议栈中负责数据传输的可靠性和准确性。
- 对整个TCP/IP协议有系统的理解:TCP/IP协议是互联网的基础,理解它的工作原理是学习网络编程的关键。
- 对TCP/IP协议体系下的其他重要协议和技术有一定的了解:除了TCP和UDP,还有许多其他重要的协议,如HTTP、FTP、DNS等。
- 学会使用一些分析网络问题的工具和方法:如Wireshark、tcpdump等工具可以帮助我们分析和解决网络问题。
这些内容不仅是网络编程的理论基础,也是服务器开发程序员的重要基本功,更是各大公司笔试面试的核心考点。
应用层
应用层是网络协议栈的顶层,负责处理特定的应用程序数据。我们日常使用的许多网络应用程序,如浏览器、邮件客户端、聊天软件等,都是在应用层运行的。
再谈“协议”
协议是一种“约定”,是通信双方遵循的规则和标准。在网络编程中,socket API提供了读写数据的接口,这些接口通常以“字符串”的方式来发送接收数据。但如果我们需要传输“结构化的数据”怎么办呢?
网络版计算器
例如,我们需要实现一个服务器版的加法器。客户端需要发送两个加数,服务器进行计算后再返回结果给客户端。我们可以采用以下两种方案:
方案一:
- 客户端发送一个形如“1+1”的字符串;
- 字符串中有两个操作数,都是整形;
- 两个数字之间有一个字符是运算符,运算符只能是“+”;
- 数字和运算符之间没有空格;
这种方法的优点是实现简单,但缺点是扩展性差。如果需要增加其他运算符或支持浮点数计算,就需要修改协议和解析逻辑。
方案二:
- 定义结构体来表示交互的信息;
- 发送数据时将结构体按照一定规则转换成字符串,接收数据时再按照相同规则将字符串转化回结构体;
- 这个过程叫做“序列化”和“反序列化”。
// proto.h 定义通信的结构体
typedef struct Request {int a;int b;
} Request;typedef struct Response {int sum;
} Response;// client.c 客户端核心代码
Request request;
Response response;scanf("%d,%d", &request.a, &request.b);
write(fd, &request, sizeof(Request));
read(fd, &response, sizeof(Response));// server.c 服务端核心代码
Request request;
read(client_fd, &request, sizeof(request));
Response response;
response.sum = request.a + request.b;
write(client_fd, &response, sizeof(response));
这种方法的优点是扩展性强,可以很容易地增加新的字段和功能,但缺点是需要额外的序列化和反序列化过程,增加了编程复杂度。
无论采用哪种方案,只要保证一端发送的数据能够在另一端正确解析,就可以认为协议是成功的。这种约定,就是应用层协议。
HTTP协议
虽然应用层协议是我们程序员自己定的,但实际上,已经有很多前辈定义了一些现成的、非常好用的应用层协议供我们直接使用。HTTP(超文本传输协议)就是其中之一。
认识URL
平时我们俗称的“网址”其实就是URL(Uniform Resource Locator,统一资源定位符)。URL是用来标识互联网上的资源的地址。一个完整的URL包括以下几个部分:
- 协议:如http、https、ftp等;
- 主机名:如www.example.com;
- 端口号:默认为80(HTTP)或443(HTTPS),但可以指定其他端口;
- 路径:如/index.html,表示资源在服务器上的位置;
- 查询参数:如?name=John&age=30,用于传递额外的信息;
- 片段标识符:如#section1,用于标识页面内的特定位置。
urlencode和urldecode
在URL中,某些字符(如“/”、“?”、“:”等)有特殊意义,因此不能随意出现。如果某个参数需要包含这些特殊字符,就必须先对其进行转义。转义规则如下:
- 将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。
- 例如:“+”被转义成了“%2B”。
import urllib.parseoriginal_string = "Hello World!"
encoded_string = urllib.parse.quote(original_string)
decoded_string = urllib.parse.unquote(encoded_string)print("Original:", original_string)
print("Encoded:", encoded_string)
print("Decoded:", decoded_string)
urldecode就是urlencode的逆过程,用于将转义后的字符还原成原始字符。这个过程在实际应用中非常常见,特别是在处理GET请求的参数时。
HTTP协议格式
HTTP请求和响应的格式包括三部分:首行、Header和Body。
HTTP请求:
- 首行:[方法] + [URL] + [版本],例如“GET /index.html HTTP/1.1”;
- Header:请求的属性,以冒号分割的键值对,每组属性之间用\n分隔,遇到空行表示Header部分结束;
- Body:空行后面的内容都是Body,Body允许为空字符串,如果存在Body,则在Header中会有一个Content-Length属性来标识Body的长度。
HTTP响应:
- 首行:[版本号] + [状态码] + [状态码解释],例如“HTTP/1.1 200 OK”;
- Header:响应的属性,以冒号分割的键值对,每组属性之间用\n分隔,遇到空行表示Header部分结束;
- Body:空行后面的内容都是Body,Body允许为空字符串,如果存在Body,则在Header中会有一个Content-Length属性来标识Body的长度。
HTTP的方法
HTTP定义了一系列方法,用于指定对资源执行的操作。常见的方法包括:
- GET:请求获取指定资源,通常用于获取网页内容;
- POST:向指定资源提交数据进行处理,常用于提交表单数据;
- PUT:向指定资源位置上传最新内容,常用于更新资源;
- DELETE:删除指定资源,常用于删除服务器上的资源;
- HEAD:类似GET方法,但只请求资源的头部信息,不返回实际内容;
- OPTIONS:请求指定资源的通信选项和需求,通常用于跨域请求的预检;
- PATCH:对指定资源进行部分修改,常用于更新资源的一部分。
HTTP的状态码
HTTP状态码用于表示服务器对请求的处理结果。常见的状态码包括:
- 1xx(信息性状态码):
- 100 Continue:客户端应继续请求。
- 2xx(成功状态码):
- 200 OK:请求成功。
- 201 Created:请求成功并创建了新的资源。
- 3xx(重定向状态码):
- 301 Moved Permanently:资源永久移动到新位置。
- 302 Found:资源临时移动到新位置。
- 4xx(客户端错误状态码):
- 400 Bad Request:请求无效。
- 401 Unauthorized:未授权。
- 403 Forbidden:禁止访问。
- 404 Not Found:请求的资源不存在。
- 5xx(服务器错误状态码):
- 500 Internal Server Error:服务器内部错误。
- 502 Bad Gateway:无效网关。
- 503 Service Unavailable:服务不可用。
HTTP常见Header
Header是HTTP请求和响应的重要组成部分,用于传递请求和响应的元数据。常见的HTTP Header包括:
- Content-Type:表示数据类型(如text/html、application/json等);
- Content-Length:表示Body的长度;
- Host:客户端告知服务器,请求的资源在哪个主机的哪个端口上;
- User-Agent:声明用户的操作系统和浏览器版本信息;
- Referer:当前页面是从哪个页面跳转过来的;
- Location:搭配
3xx状态码使用,告诉客户端接下来要去哪里访问;
- Cookie:用于在客户端存储少量信息,通常用于实现会话(session)的功能。
User-Agent里的历史故事:User-Agent最早是用于表示浏览器的版本信息,但随着浏览器的更新换代,这个字段也变得越来越复杂。例如,早期的浏览器如Netscape和Internet Explorer都有各自的User-Agent字符串,但随着时间的推移,许多浏览器开始模仿这些字符串以提高兼容性。
最简单的HTTP服务器
实现一个最简单的HTTP服务器,只在网页上输出“hello world”。只要我们按照HTTP协议的要求构造数据,就很容易实现。
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>void Usage() {printf("usage: ./server [ip] [port]\n");
}int main(int argc, char* argv[]) {if (argc != 3) {Usage();return 1;}int fd = socket(AF_INET, SOCK_STREAM, 0);if (fd < 0) {perror("socket");return 1;}struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(argv[1]);addr.sin_port = htons(atoi(argv[2]));int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));if (ret < 0) {perror("bind");return 1;}ret = listen(fd, 10);if (ret < 0) {perror("listen");return 1;}for (;;) {struct sockaddr_in client_addr;socklen_t len;int client_fd = accept(fd, (struct sockaddr*)&client_addr, &len);if (client_fd < 0) {perror("accept");continue;}char input_buf[1024 * 10] = {0}; // 用一个足够大的缓冲区直接把数据读完。ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf) - 1);if (read_size < 0) {return 1;}printf("[Request] %s", input_buf);char buf[1024] = {0};const char* hello = "<h1>hello world</h1>";sprintf(buf, "HTTP/1.0 200 OK\nContent-Length:%lu\n\n%s", strlen(hello), hello);write(client_fd, buf, strlen(buf));}return 0;
}
备注:
- 此处使用9090端口号启动了HTTP服务器。虽然HTTP服务器一般使用80端口,但这只是一个通用的习惯,并不是说HTTP服务器就不能使用其他的端口号。
- 使用Chrome测试我们的服务器时,可以看到服务器打出的请求中还有一个“GET /favicon.ico HTTP/1.1”这样的请求。读者可以自行查找资料,理解favicon.ico的作用。
实验:把返回的状态码改成404、403、504等,观察浏览器上的效果。
传输层
传输层负责确保数据能够从发送端可靠地传输到接收端。传输层的两个主要协议是TCP和UDP。
再谈端口号
端口号(Port)标识了一个主机上进行通信的不同应用程序。在TCP/IP协议中,用“源IP”、“源端口号”、“目的IP”、“目的端口号”、“协议号”这样一个五元组来标识一个通信。
端口号范围划分
- 0 - 1023:知名端口号,HTTP、FTP、SSH等这些广为使用的应用层协议的端口号都是固定的。
- 1024 - 65535:操作系统动态分配的端口号,客户端程序的端口号由操作系统从这个范围分配。
认识知名端口号(Well-Known Port Number)
有些服务器非常常用,为了使用方便,人们约定一些常用服务器使用以下固定的端口号:
- SSH服务器,使用22端口;
- FTP服务器,使用21端口;
- Telnet服务器,使用23端口;
- HTTP服务器,使用80端口;
- HTTPS服务器,使用443端口。
我们自己写程序使用端口号时,要避开这些知名端口号。
两个问题
- 一个进程是否可以bind多个端口号?
- 一个端口号是否可以被多个进程bind?
这些问题可以通过实验和查阅相关文档来验证。
netstat
netstat是一个用来查看网络状态的重要工具。
常用选项:
- n:拒绝显示别名,能显示数字的全部转化成数字;
- l:仅列出有在Listen(监听)的服务状态;
- p:显示建立相关链接的程序名;
- t:仅显示TCP相关选项;
- u:仅显示UDP相关选项;
- a:显示所有选项,默认不显示LISTEN相关。
pidof
pidof是一个在查看服务器的进程ID时非常方便的工具。
语法:pidof [进程名]
功能:通过进程名查看进程ID。
UDP协议
UDP(User Datagram Protocol,用户数据报协议)是一种无连接、不可靠的传输层协议。
UDP协议端格式
UDP协议头包括以下字段:
- 源端口号:16位,表示发送数据的应用程序的端口号;
- 目的端口号:16位,表示接收数据的应用程序的端口号;
- 长度:16位,表示整个UDP数据报的长度(包括UDP头和数据部分);
- 校验和:16位,用于错误检测。
UDP的特点
- 无连接:知道对端的IP和端口号就可以直接进行传输,不需要建立连接;
- 不可靠:没有确认机制和重传机制,如果因为网络故障数据无法到达对方,UDP协议层不会返回任何错误信息;
- 面向数据报:不能灵活控制读写数据的次数和数量,应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并。
UDP的缓冲区
- UDP没有真正意义上的发送缓冲区。调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作;
- UDP具有接收缓冲区,但不能保证收到的UDP报文的顺序和发送顺序一致。如果缓冲区满了,再到达的UDP数据就会被丢弃。
UDP使用注意事项
- UDP协议首部中的最大长度为16位,即一个UDP报文的最大长度是64K(包含UDP首部)。
- 如果需要传输的数据超过64K,就需要在应用层手动分包,多次发送,并在接收端手动拼装。
基于UDP的应用层协议
- NFS:网络文件系统
- TFTP:简单文件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议(用于无盘设备启动)
- DNS:域名解析协议
TCP协议
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接、可靠的传输层协议。
TCP协议段格式
TCP协议头包括以下字段:
- 源/目的端口号:16位,表示数据从哪个进程来,到哪个进程去;
- 序号:32位,用于标识数据段的顺序;
- 确认号:32位,表示已成功接收的数据段序号;
- 头部长度:4位,表示TCP头部的长度;
- 标志位:6位,包括URG、ACK、PSH、RST、SYN、FIN;
- 窗口大小:16位,用于流量控制;
- 校验和:16位,用于错误检测;
- 紧急指针:16位,标识紧急数据的位置;
- 选项:可选字段,用于扩展TCP功能。
确认应答(ACK)机制
TCP将每个字节的数据都进行了编号,即为序列号。每一个ACK都带有对应的确认序列号,告诉发送者哪些数据已被接收,下一次从哪里开始发送。
超时重传机制
如果发送的数据在特定时间内没有收到确认应答,发送端会进行重发。这个时间间隔根据网络环境动态计算。
连接管理机制
TCP要经过三次握手建立连接,四次挥手断开连接。连接建立和断开的具体流程如下:
服务端状态转换:
- CLOSED -> LISTEN:服务器端调用listen后进入LISTEN状态,等待客户端连接;
- LISTEN -> SYN_RCVD:监听到连接请求后,进入SYN_RCVD状态,并向客户端发送SYN确认报文;
- SYN_RCVD -> ESTABLISHED:收到客户端确认报文后,进入ESTABLISHED状态,可以进行数据读写;
- ESTABLISHED
-> CLOSE_WAIT:客户端主动关闭连接,服务器收到结束报文段后进入CLOSE_WAIT状态;
- CLOSE_WAIT -> LAST_ACK:服务器调用close关闭连接后,发送FIN报文,进入LAST_ACK状态,等待客户端确认;
- LAST_ACK -> CLOSED:收到客户端的确认后,彻底关闭连接。
客户端状态转换:
- CLOSED -> SYN_SENT:客户端调用connect,发送同步报文段;
- SYN_SENT -> ESTABLISHED:connect调用成功后进入ESTABLISHED状态,开始数据读写;
- ESTABLISHED -> FIN_WAIT_1:客户端主动调用close时,向服务器发送结束报文段,进入FIN_WAIT_1;
- FIN_WAIT_1 -> FIN_WAIT_2:收到服务器确认后进入FIN_WAIT_2,等待服务器的结束报文段;
- FIN_WAIT_2 -> TIME_WAIT:收到服务器的结束报文段后,进入TIME_WAIT,发送最后的ACK;
- TIME_WAIT -> CLOSED:等待2MSL(Max Segment Life,报文最大生存时间)后,进入CLOSED状态。
理解TIME_WAIT状态
TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL的时间后才能回到CLOSED状态。这是为了保证最后一个报文可靠到达,防止重启服务器时收到错误的迟到数据。
解决TIME_WAIT状态引起的bind失败的方法
在某些情况下,服务器需要处理大量客户端连接,每个连接的生存时间很短,但连接请求频繁。此时,可以使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,允许创建端口号相同但IP地址不同的多个socket描述符。
理解CLOSE_WAIT状态
如果服务器上出现大量CLOSE_WAIT状态,说明服务器没有正确关闭socket,导致四次挥手没有正确完成。只需要在合适的位置加上close()即可解决问题。
滑动窗口
滑动窗口机制允许发送端在未收到确认应答前发送多个数据段,大大提高了传输效率。窗口大小表示无需等待确认应答而可以继续发送数据的最大值。窗口越大,网络的吞吐率越高。
流量控制
接收端通过TCP头部中的窗口大小字段告知发送端当前缓冲区的剩余空间,发送端根据窗口大小调整发送速度,防止缓冲区溢出。
拥塞控制
TCP引入慢启动机制,在不清楚网络状态的情况下,先发少量数据探测,逐步增加发送量。拥塞窗口(cwnd)初始为1,每次收到ACK后增加1,超过慢启动阈值后,按线性增长。
延迟应答和捎带应答
延迟应答通过稍微延迟ACK的发送时间,增加窗口大小,提高传输效率。捎带应答则利用应用层的响应数据捎带ACK一起发送。
面向字节流
TCP连接在内核中维护一个发送缓冲区和接收缓冲区,数据在缓冲区中进行处理,保证传输的可靠性和顺序性。TCP连接是全双工的,既可以读数据,也可以写数据。
粘包问题
粘包问题是指应用层看到的一串连续字节数据中无法区分出每个完整的数据包。解决方法包括:
- 对于定长包,按照固定大小读取;
- 对于变长包,在包头约定一个包总长度字段或使用明确的分隔符。
TCP异常情况
- 进程终止:释放文件描述符,发送FIN,正常关闭连接。
- 机器重启:与进程终止相同。
- 机器掉电/网线断开:接收端发现连接已断开,进行重置或通过保活定时器释放连接。
TCP小结
TCP通过一系列复杂的机制保证传输的可靠性和高效性。这些机制包括校验和、序列号、确认应答、超时重发、连接管理、流量控制和拥塞控制等。
基于TCP的应用层协议
- HTTP
- HTTPS
- SSH
- Telnet
- FTP
- SMTP
当然,还包括我们自己定义的应用层协议。
TCP/UDP对比
TCP和UDP各有优缺点,适用于不同的场景。TCP适用于可靠传输,如文件传输和重要状态更新;UDP适用于对高速传输和实时性要求较高的通信,如视频传输和广播。
用UDP实现可靠传输(经典面试题)
参考TCP的可靠性机制,在应用层实现类似的逻辑,包括序列号、确认应答和超时重传等。
TCP相关实验
通过实验理解listen的第二个参数、使用Wireshark分析TCP通信流程等,进一步掌握TCP协议的工作原理和实际应用。
理解 listen 的第二个参数
在TCP服务器编程中,listen函数的第二个参数表示监听队列的最大长度。这个参数的值决定了内核为该套接字维护的两个队列的长度:
- 半连接队列(SYN Queue):存放处于SYN_RECV状态的连接请求。
- 全连接队列(Accept Queue):存放已完成三次握手,但应用程序尚未调用
accept取走的连接。
当一个新的连接请求到达时,内核首先将其放入半连接队列。如果客户端发送的SYN报文被确认,连接进入全连接队列。如果全连接队列已满,新的连接请求将被拒绝。
#include "tcp_socket.hpp"int main(int argc, char* argv[]) {if (argc != 3) {printf("Usage ./test_server [ip] [port]\n");return 1;}TcpSocket sock;bool ret = sock.Bind(argv[1], atoi(argv[2]));if (!ret) {return 1;}ret = sock.Listen(2);if (!ret) {return 1;}// 客户端不进行 acceptwhile (1) {sleep(1);}return 0;
}
使用 Wireshark 分析 TCP 通信流程
Wireshark是一个强大的网络协议分析工具,可以抓取和分析网络通信数据包。以下是使用Wireshark分析TCP通信流程的步骤:
下载和安装 Wireshark
可以从Wireshark官方网站下载并安装最新版本的Wireshark。
启用 telnet 客户端
在Windows上启用telnet客户端,参考百度经验。
启动 Wireshark 并设置过滤器
启动Wireshark后,在过滤器栏中输入ip.addr == [服务器 ip]或tcp.port == 9090,以只抓取指定IP或端口的数据包。
观察三次握手过程
启动服务器后,使用telnet客户端连接服务器,抓取数据包并观察三次握手过程。可以看到三个报文各自的序列号和确认序号的规律。
telnet [ip] [port]
观察确认应答
在telnet中输入一个字符,可以看到客户端发送一个长度为1字节的数据,服务器返回ACK和响应数据,然后客户端反馈ACK。
观察四次挥手
在telnet中输入ctrl + ]回到控制界面,输入quit退出,可以观察四次挥手的过程。
结语
网络基础是现代计算机科学的重要组成部分,掌握网络编程的理论和实践,不仅有助于理解计算机系统的运行机制,还能提高开发高性能、可靠网络应用的能力。希望本篇文章能帮助读者从入门到精通,全面掌握网络基础知识。
嗯,就是这样啦,文章到这里就结束啦,真心感谢你花时间来读。
觉得有点收获的话,不妨给我点个赞吧!
如果发现文章有啥漏洞或错误的地方,欢迎私信我或者在评论里提醒一声~
相关文章:
从入门到精通:网络基础详解
前言 在现代社会,网络技术已经成为我们日常生活和工作中不可或缺的一部分。从简单的网页浏览到复杂的分布式系统,网络技术都扮演着至关重要的角色。通过这篇文章,读者将从入门到精通,全面掌握网络编程的理论和实践。 重点摘要 …...
初步理解三__《面向互联网大数据的威胁情报 并行挖掘技术研究》
初步理解三 5类战术标签 gtp 收集开源的网络安全报告并将其转化为统一的文本格式,并且标注了5类战术标签是一个涉及到数据处理和分类的复杂任务。以下是一种可能的处理方法: 数据收集和整合: 使用网络爬虫或API访问工具收集开源的网络安全…...
【C++修行之道】string类的使用
目录 一.C语言中的字符串 二、标准库中的string类 (了解) 2.1 string类(了解) 2.2 帮助文档阅读 三、 string类的常用接口说明 3.1 string类对象的常见构造 3.2 string类对象的容量操作 3.3 string类对象的访问及遍历操作 字符串类的简单实现 3.4 string类对象的修改…...
云原生监控-Kubernetes-Promethues-Grafana
云原生监控-Prometheus 作者:行癫(盗版必究) 引读:本文章所涉及到技术点包括Prometheus、Grafana、Kuebrnetes;Prometheus基于外部构建采集并监控Kubernetes集群以及集群中的应用,例如使用mysql-node-exporter、nginx-node-exporter采集Kuebrnetes集群中的应用数据,使用…...
MySQL高级----InnoDB引擎
逻辑存储结构 表空间 表空间(ibd文件),一个mysql实例可以对应多个表空间,用于存储记录、索引等数据。 段 段,分为数据段(Leaf node segment)、索引段(Non-leaf node segment)、回滚段(Rollback segment),InnoDB是…...
Docker定时清理
一、循环调度执行 1、检查cron状态 systemctl status crond 2、创建要执行的shell脚本 vim /home/cleanup_docker.sh #! /bin/bash # 清理临时文件 echo $(date "%H:%M:%S") "执行docker清理命令..." docker system prune -af-a 清理包括未使用的镜像 …...
mysql之导入测试数据
运维时经常要这样:mysql改表名,创建一个一样的表不含数据,复制旧表几条数据进去 改变表的名字: RENAME TABLE old_table_name TO new_table_name; 这将把原来的表old_table_name重命名为new_table_name。 创建一个一样的表结构…...
WPScan漏洞扫描工具的介绍及使用
目录 1. 介绍2. 常用参数 1. 介绍 WPScan是Kali Linux默认自带的一款漏洞扫描工具,它采用Ruby编写,能够扫描WordPress网站中的多种安全漏洞,其中包括WordPress本身的漏洞、插件漏洞和主题漏洞,最新版本WPScan的数据库中包含超过18…...
基于单片机的饲料搅拌机控制系统设计
摘要 : 文章主要从软件和硬件两个部分对基于单片机的饲料搅拌机控制系统进行研究设计 。 硬件部分主要由传感器模块 、 信号采集模块、 键盘接入模块 、 LED 显示模块 、 继电器模块以及看门狗模块组成 。 软件部分在 KeilC51 软件基础上重点对控制系统主程序 、…...
Mysql笔记-v2
零、 help、\h、? 调出帮助 mysql> \hFor information about MySQL products and services, visit:http://www.mysql.com/ For developer information, including the MySQL Reference Manual, visit:http://dev.mysql.com/ To buy MySQL Enterprise support, training, …...
Java SpringBoot MongoPlus 使用MyBatisPlus的方式,优雅的操作MongoDB
Java SpringBoot MongoPlus 使用MyBatisPlus的方式,优雅的操作MongoDB 介绍特性安装新建SpringBoot工程引入依赖配置文件 使用新建实体类创建Service测试类进行测试新增方法查询方法 官方网站获取本项目案例代码 介绍 Mongo-Plus(简称 MP)是一…...
【易捷海购-注册安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...
antd+vue——实现table组件跨页多选,已选择数据禁止第二次重复选择
需求场景:点击【新增】按钮可以在分页弹窗中跨页多选选择数据后添加到页面中,再次点击【新增】,已经选择过的数据则置灰不让重复选择。 选择后,置灰 点击【确定】数据添加到页面中,可再次点击【新增】进行添加数据 …...
Python采集京东标题,店铺,销量,价格,SKU,评论,图片
京东的许多数据是通过 JavaScript 动态加载的,包括销量、价格、评论和评论时间等信息。我们无法仅通过传统的静态网页爬取方法获取到这些数据。需要使用到如 Selenium 或 Pyppeteer 等能够模拟浏览器行为的工具。 另外,京东的评论系统是独立的一个系统&a…...
数据中台指标管理系统
您所描述的是一个数据中台指标管理系统,它基于Spring Cloud技术栈构建。数据中台是企业数据管理和应用的中心平台,它整合了企业内外部的数据资源,提供数据服务和数据管理能力。以下是您提到的各个模块的简要概述: 1. **首页**&am…...
什么是ThreadLocal以及内存泄漏问题、hash冲突问题
ThreadLocal是什么 ThreadLocal类用来提供线程内部的局部变量 它主要有三大特性: 线程安全: 在多线程并发的场景下保证线程安全传递数据:通过ThreadLocal在同一线程传递公共变量线程隔离:每个线程的变量都是独立的,不会互相影响…...
从零开始做题:My_lllp
题目 给出一张png图片 解题 ┌──(holyeyes㉿kali2023)-[~/Misc/题目/zulu/My_lllp] └─$ python2 lsb.py extract my_lllp.png out.txt my_lllp [] Image size: 1080x1079 pixels. [] Written extracted data to out.txt. ┌──(holyeyes㉿kali2023)-[~/Misc/题目/zul…...
如何编译ffmpeg支持h265(hevc)?
推荐使用这里的文件:https://github.com/runner365/ffmpeg_rtmp_h265 根据你ffmpeg的源码 版本,切换到不同分支即可。 国内cdn方式: 新增codecid hevc/vp8/vp9/opus在rtmp中的codecid没有官方协议定义,由国内众多知名cdn共同制定。 FLV_COD…...
UNIAPP_顶部导航栏右侧添加uni-icons图标,并绑定点击事件,自定义导航栏右侧图标
效果 1、导入插件 uni-icons插件:https://ext.dcloud.net.cn/plugin?nameuni-icons 复制 uniicons.ttf 文件到 static/fonts/ 下 仅需要那个uniicons.ttf文件,不引入插件、单独把那个文件下载到本地也是可以的 2、配置页面 "app-plus":…...
Redis原理-数据结构
Redis原理篇 1、原理篇-Redis数据结构 1.1 Redis数据结构-动态字符串 我们都知道Redis中保存的Key是字符串,value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串,因为C语言字符串存…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
