《Linux 网络架构:基于 TCP 协议的多人聊天系统搭建详解》
一、系统概述
本系统是一个基于 TCP 协议的多人聊天系统,由一个服务器和多个客户端组成。客户端可以连接到服务器,向服务器发送消息,服务器接收到消息后将其转发给其他客户端,实现多人之间的实时聊天。系统使用 C 语言编写,利用了 Unix 系统的网络编程接口和多线程、I/O 多路复用等技术。
二、文件结构
server.c
:服务器端程序,负责监听客户端连接、接收客户端消息并将消息转发给其他客户端。client1.c
:客户端程序,使用poll
函数实现 I/O 多路复用,同时处理用户输入和服务器消息。client2.c
:客户端程序,使用多线程技术,一个线程负责接收服务器消息,另一个线程负责处理用户输入。
三、代码详细分析
1. 数据包结构体
在三个文件中都定义了相同的数据包结构体 Packet
,用于在客户端和服务器之间传输数据。
typedef struct {int type; // 0 for message, 1 for disconnectchar data[BUFFER_SIZE];
} Packet;
type
:数据包类型,0 表示消息,1 表示断开连接。data
:数据包携带的数据,最大长度为BUFFER_SIZE
。
2. 服务器端程序(server.c)
2.1 主要变量
server_fd
:服务器套接字文件描述符。client_fd
:客户端套接字文件描述符。max_fd
:记录最大的文件描述符,用于select
函数。activity
:记录select
函数返回的活动文件描述符数量。valread
:记录从客户端读取的数据长度。server_addr
:存储服务器的地址信息。client_addr
:存储客户端的地址信息。client_sockets
:数组用于存储所有客户端的套接字文件描述符。readfds
:文件描述符集合,用于select
函数监听可读事件。
2.2 主要步骤
- 创建套接字:使用
socket
函数创建一个 TCP 套接字。 - 绑定地址:使用
bind
函数将套接字绑定到指定的地址和端口。 - 监听连接:使用
listen
函数开始监听客户端连接。 - 循环处理:使用
select
函数监听服务器套接字和客户端套接字的可读事件。- 若服务器套接字有可读事件,说明有新的客户端连接请求,使用
accept
函数接受连接。 - 若客户端套接字有可读事件,从客户端读取数据包,根据数据包类型进行相应处理。
- 若数据包类型为消息,将消息转发给其他客户端。
- 若数据包类型为断开连接或读取到的数据长度为 0,说明客户端断开连接,关闭客户端套接字。
- 若服务器套接字有可读事件,说明有新的客户端连接请求,使用
3. 客户端程序(client1.c)
3.1 主要变量
client_fd
:客户端套接字文件描述符。server_addr
:存储服务器的地址信息。packet
:用于存储要发送或接收的数据包。fds
:数组用于存储要监听的文件描述符及其事件。
3.2 主要步骤
- 创建套接字:使用
socket
函数创建一个 TCP 套接字。 - 连接服务器:使用
connect
函数连接到服务器。 - 初始化
poll
结构体:监听标准输入和客户端套接字的可读事件。 - 循环处理:使用
poll
函数监听文件描述符集合中的可读事件。- 若标准输入有可读事件,从标准输入读取数据,设置数据包类型为消息,发送给服务器。
- 若客户端套接字有可读事件,从服务器读取数据包,根据数据包类型进行相应处理。
- 若数据包类型为消息,输出接收到的消息。
- 若数据包类型为断开连接或读取数据失败,说明服务器断开连接,关闭客户端套接字,跳出循环。
4. 客户端程序(client2.c)
4.1 主要变量
client_fd
:客户端套接字文件描述符。server_addr
:存储服务器的地址信息。packet
:用于存储要发送或接收的数据包。thread_id
:存储线程的标识符。
4.2 主要步骤
- 创建套接字:使用
socket
函数创建一个 TCP 套接字。 - 连接服务器:使用
connect
函数连接到服务器。 - 创建线程:创建一个线程来接收服务器发送的消息。
- 循环处理:在主线程中,从标准输入读取数据,设置数据包类型为消息,发送给服务器。
- 线程函数:在子线程中,持续接收服务器消息,根据数据包类型进行相应处理。
- 若数据包类型为消息,输出接收到的消息。
- 若数据包类型为断开连接或读取数据失败,说明服务器断开连接,关闭客户端套接字,退出程序。
四、编译和运行
4.1 编译
gcc server.c -o server
gcc client1.c -o client1
gcc client2.c -o client2 -lpthread
4.2 运行
- 启动服务器:
./server
- 启动客户端:
./client1
./client2
4.3运行结果展示
五、源码
5.1服务器端程序(server.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>// 定义服务器监听的端口号
#define PORT 8080
// 定义数据缓冲区的大小
#define BUFFER_SIZE 1024
// 定义服务器允许的最大客户端连接数
#define MAX_CLIENTS 10/*** 定义数据包结构体,用于在服务器和客户端之间传输数据* type 数据包类型,0 表示消息,1 表示断开连接* data 数据包携带的数据*/
typedef struct {int type; // 0 for message, 1 for disconnectchar data[BUFFER_SIZE];
} Packet;/*** 主函数,服务器程序的入口点* @return 程序的退出状态码,0 表示正常退出*/
int main() {// server_fd 为服务器套接字文件描述符,client_fd 为客户端套接字文件描述符// max_fd 记录最大的文件描述符,用于 select 函数// activity 记录 select 函数返回的活动文件描述符数量// valread 记录从客户端读取的数据长度int server_fd, client_fd, max_fd, activity, valread;// server_addr 存储服务器的地址信息,client_addr 存储客户端的地址信息struct sockaddr_in server_addr, client_addr;// client_len 存储客户端地址结构体的长度socklen_t client_len = sizeof(client_addr);// packet 用于存储从客户端接收的数据包Packet packet;// client_sockets 数组用于存储所有客户端的套接字文件描述符int client_sockets[MAX_CLIENTS] = {0};// readfds 是一个文件描述符集合,用于 select 函数监听可读事件fd_set readfds;// 创建服务器套接字,使用 IPv4 地址族和 TCP 协议if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {// 若套接字创建失败,输出错误信息并退出程序perror("socket failed");exit(EXIT_FAILURE);}// 设置服务器地址信息server_addr.sin_family = AF_INET;// 监听所有可用的网络接口server_addr.sin_addr.s_addr = INADDR_ANY;// 将端口号从主机字节序转换为网络字节序server_addr.sin_port = htons(PORT);// 将服务器套接字绑定到指定的地址和端口if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {// 若绑定失败,输出错误信息,关闭套接字并退出程序perror("bind failed");close(server_fd);exit(EXIT_FAILURE);}// 开始监听客户端连接,允许的最大连接请求队列长度为 3if (listen(server_fd, 3) < 0) {// 若监听失败,输出错误信息,关闭套接字并退出程序perror("listen");close(server_fd);exit(EXIT_FAILURE);}// 输出服务器启动信息,显示监听的端口号printf("Server started on port %d\n", PORT);// 进入无限循环,持续处理客户端连接和数据while (1) {// 清空文件描述符集合FD_ZERO(&readfds);// 将服务器套接字添加到文件描述符集合中,监听其可读事件FD_SET(server_fd, &readfds);// 初始化最大文件描述符为服务器套接字文件描述符max_fd = server_fd;// 遍历客户端套接字数组for (int i = 0; i < MAX_CLIENTS; i++) {// 获取当前客户端的套接字文件描述符int sd = client_sockets[i];if (sd > 0) {// 若该客户端套接字有效,将其添加到文件描述符集合中FD_SET(sd, &readfds);}if (sd > max_fd) {// 更新最大文件描述符max_fd = sd;}}// 调用 select 函数监听文件描述符集合中的可读事件,无超时时间activity = select(max_fd + 1, &readfds, NULL, NULL, NULL);if ((activity < 0) && (errno != EINTR)) {// 若 select 函数调用失败且不是被信号中断,输出错误信息perror("select error");}if (FD_ISSET(server_fd, &readfds)) {// 若服务器套接字有可读事件,说明有新的客户端连接请求if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0) {// 若接受连接失败,输出错误信息并继续循环perror("accept");continue;}// 输出新客户端连接的信息,包括套接字文件描述符、IP 地址和端口号printf("New connection, socket fd is %d, ip is : %s, port : %d\n",client_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));// 遍历客户端套接字数组,找到一个空闲位置存储新客户端的套接字文件描述符for (int i = 0; i < MAX_CLIENTS; i++) {if (client_sockets[i] == 0) {client_sockets[i] = client_fd;break;}}}// 遍历客户端套接字数组,检查每个客户端是否有可读事件for (int i = 0; i < MAX_CLIENTS; i++) {int sd = client_sockets[i];if (FD_ISSET(sd, &readfds)) {// 从客户端读取数据包valread = read(sd, &packet, sizeof(Packet));if (valread == 0) {// 若读取到的数据长度为 0,说明客户端断开连接getpeername(sd, (struct sockaddr*)&client_addr, &client_len);// 输出客户端断开连接的信息,包括 IP 地址和端口号printf("Host disconnected, ip %s, port %d\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));// 关闭客户端套接字close(sd);// 将该位置的客户端套接字文件描述符置为 0,表示空闲client_sockets[i] = 0;} else {if (packet.type == 0) {// 若数据包类型为消息,输出接收到的消息printf("Received from client %d: %s", sd, packet.data);// 将消息转发给其他客户端for (int j = 0; j < MAX_CLIENTS; j++) {if (client_sockets[j] != sd && client_sockets[j] != 0) {// 发送数据包给其他客户端send(client_sockets[j], &packet, sizeof(Packet), 0);}}} else if (packet.type == 1) {// 若数据包类型为断开连接,输出客户端断开连接的信息printf("Client %d disconnected\n", sd);// 关闭客户端套接字close(sd);// 将该位置的客户端套接字文件描述符置为 0,表示空闲client_sockets[i] = 0;}}}}}return 0;
}
5.2客户端程序(client1.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>// 定义服务器监听的端口号
#define PORT 8080
// 定义数据缓冲区的大小
#define BUFFER_SIZE 1024/*** 定义数据包结构体,用于在客户端和服务器之间传输数据* type 数据包类型,0 表示消息,1 表示断开连接* data 数据包携带的数据*/
typedef struct {int type; // 0 for message, 1 for disconnectchar data[BUFFER_SIZE];
} Packet;/*** 主函数,客户端程序的入口点* @return 程序的退出状态码,0 表示正常退出*/
int main() {// client_fd 为客户端套接字文件描述符int client_fd;// server_addr 存储服务器的地址信息struct sockaddr_in server_addr;// packet 用于存储要发送或接收的数据包Packet packet;// fds 数组用于存储要监听的文件描述符及其事件struct pollfd fds[2];// 创建客户端套接字,使用 IPv4 地址族和 TCP 协议if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {// 若套接字创建失败,输出错误信息并退出程序perror("socket failed");exit(EXIT_FAILURE);}// 设置服务器地址信息server_addr.sin_family = AF_INET;// 将端口号从主机字节序转换为网络字节序server_addr.sin_port = htons(PORT);// 将服务器的 IP 地址转换为网络字节序server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");// 连接到服务器if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {// 若连接失败,输出错误信息,关闭套接字并退出程序perror("connect");close(client_fd);exit(EXIT_FAILURE);}// 输出连接成功的信息printf("Connected to server\n");// 初始化 poll 结构体// 监听标准输入的可读事件fds[0].fd = STDIN_FILENO;fds[0].events = POLLIN;// 监听客户端套接字的可读事件fds[1].fd = client_fd;fds[1].events = POLLIN;// 进入无限循环,持续处理输入和服务器消息while (1) {// 调用 poll 函数监听文件描述符集合中的可读事件,无超时时间int activity = poll(fds, 2, -1);if ((activity < 0) && (errno != EINTR)) {// 若 poll 函数调用失败且不是被信号中断,输出错误信息perror("poll error");}if (fds[0].revents & POLLIN) {// 若标准输入有可读事件// 清空数据包的数据部分memset(packet.data, 0, BUFFER_SIZE);if (fgets(packet.data, BUFFER_SIZE, stdin) != NULL) {// 若成功从标准输入读取数据// 设置数据包类型为消息packet.type = 0;// 发送数据包给服务器send(client_fd, &packet, sizeof(Packet), 0);}}if (fds[1].revents & POLLIN) {// 若客户端套接字有可读事件// 清空数据包memset(&packet, 0, sizeof(Packet));if (read(client_fd, &packet, sizeof(Packet)) > 0) {// 若成功从服务器读取数据if (packet.type == 0) {// 若数据包类型为消息,输出接收到的消息printf("Received from server: %s", packet.data);} else if (packet.type == 1) {// 若数据包类型为断开连接,输出服务器断开连接的信息printf("Server disconnected\n");// 关闭客户端套接字close(client_fd);// 跳出循环break;}} else {// 若读取数据失败,说明服务器断开连接printf("Server disconnected\n");// 关闭客户端套接字close(client_fd);// 跳出循环break;}}}// 关闭客户端套接字close(client_fd);return 0;
}
5.3客户端程序(client2.c)
// 包含标准输入输出库,用于使用 printf、perror 等函数进行输入输出操作
#include <stdio.h>
// 包含标准库,提供 exit 等函数用于程序退出等操作
#include <stdlib.h>
// 包含字符串处理库,提供 memset、strlen 等字符串操作函数
#include <string.h>
// 包含 Unix 标准库,提供 close、read、write 等系统调用函数
#include <unistd.h>
// 包含网络地址转换库,提供 inet_ntoa、htons 等网络地址转换函数
#include <arpa/inet.h>
// 包含线程相关的头文件,用于创建和管理线程
#include <pthread.h>// 定义服务器监听的端口号
#define PORT 8080
// 定义数据缓冲区的大小
#define BUFFER_SIZE 1024/*** 定义数据包结构体,用于在客户端和服务器之间传输数据* type 数据包类型,0 表示消息,1 表示断开连接* data 数据包携带的数据*/
typedef struct {int type; // 0 for message, 1 for disconnectchar data[BUFFER_SIZE];
} Packet;// 全局变量,存储客户端套接字文件描述符
int client_fd;/*** 线程函数,用于接收服务器发送的消息* arg 线程函数的参数,此处未使用* @return 线程返回值,此处为 NULL*/
void *receive_messages(void *arg) {// 定义数据包变量,用于存储从服务器接收的数据包Packet packet;// 进入无限循环,持续接收服务器消息while (1) {// 清空数据包memset(&packet, 0, sizeof(Packet));if (read(client_fd, &packet, sizeof(Packet)) > 0) {// 若成功从服务器读取数据if (packet.type == 0) {// 若数据包类型为消息,输出接收到的消息printf("Received from server: %s", packet.data);} else if (packet.type == 1) {// 若数据包类型为断开连接,输出服务器断开连接的信息printf("Server disconnected\n");// 关闭客户端套接字close(client_fd);// 退出程序,返回失败状态exit(EXIT_FAILURE);}} else {// 若读取数据失败,说明服务器断开连接printf("Server disconnected\n");// 关闭客户端套接字close(client_fd);// 退出程序,返回失败状态exit(EXIT_FAILURE);}}return NULL;
}/*** 主函数,客户端程序的入口点* @return 程序的退出状态码,0 表示正常退出*/
int main() {// server_addr 存储服务器的地址信息struct sockaddr_in server_addr;// packet 用于存储要发送的数据包Packet packet;// thread_id 存储线程的标识符pthread_t thread_id;// 创建客户端套接字,使用 IPv4 地址族和 TCP 协议if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {// 若套接字创建失败,输出错误信息并退出程序perror("socket failed");exit(EXIT_FAILURE);}// 设置服务器地址信息server_addr.sin_family = AF_INET;// 将端口号从主机字节序转换为网络字节序server_addr.sin_port = htons(PORT);// 将服务器的 IP 地址转换为网络字节序server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");// 连接到服务器if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {// 若连接失败,输出错误信息,关闭套接字并退出程序perror("connect");close(client_fd);exit(EXIT_FAILURE);}// 输出连接成功的信息printf("Connected to server\n");// 创建线程来接收消息if (pthread_create(&thread_id, NULL, receive_messages, NULL) != 0) {// 若线程创建失败,输出错误信息,关闭套接字并退出程序perror("pthread_create");close(client_fd);exit(EXIT_FAILURE);}// 进入无限循环,持续从标准输入读取数据并发送给服务器while (1) {// 清空数据包的数据部分memset(packet.data, 0, BUFFER_SIZE);if (fgets(packet.data, BUFFER_SIZE, stdin) != NULL) {// 若成功从标准输入读取数据// 设置数据包类型为消息packet.type = 0;// 发送数据包给服务器send(client_fd, &packet, sizeof(Packet), 0);}}// 关闭客户端套接字close(client_fd);return 0;
}
相关文章:
《Linux 网络架构:基于 TCP 协议的多人聊天系统搭建详解》
一、系统概述 本系统是一个基于 TCP 协议的多人聊天系统,由一个服务器和多个客户端组成。客户端可以连接到服务器,向服务器发送消息,服务器接收到消息后将其转发给其他客户端,实现多人之间的实时聊天。系统使用 C 语言编写&#x…...
知识蒸馏:让大模型“瘦身”的魔法
知识蒸馏:让大模型“瘦身”的魔法 什么是蒸馏模型?AI界的“知识浓缩术”核心定义传统训练 vs 知识蒸馏关键优势 DeepSeek的蒸馏“三步魔法”骨架提取——搭建“迷你版大脑”知识灌注——模仿教师的“思考过程”微调优化——针对场景“查漏补缺” DeepSee…...
MySQL数据库精研之旅第一期:开启数据管理新旅程
专栏:MySQL数据库成长记 个人主页:手握风云 目录 一、数据库简介 1.1. 数据库的概念 1.2. 数据库和数据结构的关系 1.3. 主流数据库 1.3.1. 关系型数据库 1.3.2. 非关系型数据库 1.4. 关系型数据库的概念 二、MySQL配置 2.1. mysqld服务端程序 …...
Linux复习——基础IO,认识文件描述符、软硬件链接
1.复习C文件接口 1.1 fopen FILE *fopen(const char *path, const char *mode); path:带路径的文件名称(待打开的文件) mode: r:以可读方式打开,不可写,文件不存在,则报错 r&…...
【Java集合夜话】第1篇:拨开迷雾,探寻集合框架的精妙设计
欢迎来到Java集合框架系列的第一篇文章!🌹 本系列文章将以通俗易懂的语言,结合实际开发经验,带您深入理解Java集合框架的设计智慧。🌹 若文章中有任何不准确或需要改进的地方,欢迎大家指出,让我…...
Prometheus使用
介绍:Prometheus 是一个开源的 监控与告警系统,主要用于采集和存储时间序列数据(Time Series Data) Prometheus的自定义查询语言PromQL Metric类型 为了能够帮助用户理解和区分这些不同监控指标之间的差异,Prometheu…...
Java学习打卡-Day19-Set、HashSet、LinkedHashSet
Set 接口 无序(添加和取出顺序不一致)(但取出顺序固定)。没有索引。不允许重复,所以最多一个null。遍历方式 迭代器增强for循环不能使用普通for循环索引方式。 HashSet 实现了Set接口,具有相应特征。底…...
冯・诺依曼架构深度解析
一、历史溯源:计算机科学的革命性突破 1.1 前冯・诺依曼时代 在 1940 年代之前,计算机领域呈现 "百家争鸣" 的格局: 哈佛 Mark I(1944):采用分离的指令存储与数据存储ENIAC(1946&a…...
单片机学完开发板,如何继续提升自己的技能?
很多人学完开发板后都会卡在一个尴尬的阶段:觉得自己会的东西不少,但又不知道下一步该干啥。会点C语言,能烧录程序,能点亮LED,玩转按键,搞定串口等等,能用开发板做点小玩意儿,但面对…...
Nginx 日志格式
默认日志格式配置 log_format main $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for";该格式记录了客户端IP、用户、时间、请求、状态…...
Spring Boot 整合 Elasticsearch 实践:从入门到上手
引言 Elasticsearch 是一个开源的分布式搜索引擎,广泛用于日志分析、搜索引擎、数据分析等场景。本文将带你通过一步步的教程,在 Spring Boot 项目中整合 Elasticsearch,轻松实现数据存储与查询。 1. 创建 Spring Boot 项目 首先ÿ…...
STM32 —— 嵌入式系统、通用计算机系统、物联网三层架构
目录 一、嵌入式系统的概念 二、通用计算机系统与嵌入式系统的比较 用途 硬件 软件 性能与功耗 开发与维护 三、嵌入式系统与物联网的关系 四、物联网的三层架构 1. 感知层(Perception Layer) 2. 网络层(Network Layer) …...
SARAD 解读
出处:NIPS 2024 代码链接:https://github.com/daidahao/SARAD/ 一 文章动机 ① 时间建模(Temporal Modeling)的局限性: a. 时间维度上 感受野极小;b. 变量间时间戳错位 (时间建模、空间建模不统一) →…...
【愚公系列】《高效使用DeepSeek》017-知识点思维导图生成
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...
【linux】scp和rsync
scp 和 rsync 都是 Linux 系统中用于文件传输的命令行工具,它们都可以通过网络在本地和远程主机之间传输文件。 scp 命令 定义 scp 是 “secure copy” 的缩写,它是一个基于 SSH 协议的文件传输工具,用于在本地和远程主机之间安全地复制文…...
软件需求分类、需求获取(高软46)
系列文章目录 软件需求分类,需求获取 文章目录 系列文章目录前言一、软件需求二、获取需求三、真题总结 前言 本节讲明软件需求分类、需求获取的相关知识。 一、软件需求 二、获取需求 三、真题 总结 就是高软笔记,大佬请略过!...
蓝桥杯单片机之AT24C02(基于自己对AT24C02的学习和理解)
一、先用抽象法说明原理,让原理变得简单易懂: 1、向AT24C02写入数据: 有个关系户,他想安排自己的儿子进某个大厦里某个楼层的公司,那么他就要先找到这个公司的地址,然后再找到该公司是第几楼,最…...
【Qt】Qt + Modbus 服务端学习笔记
《Qt Modbus 服务端学习笔记》 1.因为项目的需要,要写一个modbus通信,csdn上感觉有些回答,代码是人工智能生成的,有些细节不对。我这个经过实测,是可以直接用的。 首先要包含Qt 的相关模块 Qt Modbus 模块主要包含以…...
抖音用户视频批量下载工具开发全解析
一、逆向工程原理剖析 1.1 抖音Web端防护体系 抖音采用五层防御机制保护数据接口: graph LRA[浏览器指纹检测] --> B[请求参数签名]B --> C[Cookie动态验证]C --> D[请求频率限制]D --> E[IP信誉评级] 1.2 核心参数解密 参数名称作用原理生成方式有效期x-bogu…...
DeepSeek写打台球手机小游戏
DeepSeek写打台球手机小游戏 提问 根据提的要求,让DeepSeek整理的需求,进行提问,内容如下: 请生成一个包含以下功能的可运行移动端打台球小游戏H5文件: 要求 可以重新开始游戏 可以暂停游戏 有白球和其他颜色的球&am…...
清晰易懂的 Swift 安装与配置教程
初学者也能看懂的 Swift 安装与配置教程 本教程将手把手教你如何在 macOS 系统上安装 Swift,配置依赖包缓存位置,并指出新手容易踩坑的细节。即使你是零基础小白,也能快速上手! 一、安装 Swift(macOS 环境)…...
Post-Training Quantization, PTQ
Post-Training Quantization(PTQ) 是 模型训练完成后,对其参数(权重 & 激活值)进行量化 的方法,目的是 减少存储占用 & 提高推理速度,同时尽可能保持模型精度。 相比于 量化感知训练&a…...
linux Redhat9.5采用DNS主从实现跨网段解析
文章目录 主从服务器DNS实现跨网段解析一、服务器规划二、主服务器配置1、安装bind2、修改主配置文件3、配置区域配置文件4、配置正向解析文件5、配置反向解析文件6、检查并启动服务 三、从服务器配置1、安装bind2、配置主配置文件3、修改区域配置文件4、检查并启动服务 四、路…...
Python个人学习笔记(18):模块(异常处理、traceback、日志记录)
七、异常处理 语法错误不属于异常,处理的是程序运行时的一些意外情况 代码: a int(input(>>>:)) b int(input(>>>:)) print(a / b) # 在运行的时候由于数据不对,导致出错 # 此时程序会中断 prin…...
记一次MyBatis分页莫名其妙的失效,首次执行合适,后续执行分页失效且异常
代码几乎一样,为啥这个xml配置的就会出现莫名其妙的问题呢 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{propertymybatis_plus_first, modeI…...
Claude是什么?适合哪些场景?
Claude 是由人工智能公司 Anthropic 开发的一款 大型语言模型(LLM),旨在通过自然语言交互帮助用户完成复杂任务。以下是关于 Claude 的核心信息: 1. 核心定位 • 安全可靠: 采用 Constitutional AI(宪法AI…...
基于yolov11的持刀检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面
【算法介绍】 基于YOLOv11的持刀检测系统 随着公共安全问题的日益突出,特别是在公共场所如机场、车站、学校等地,持刀等危险行为频发,对人们的生命财产安全构成严重威胁。传统的监控手段往往依赖于人工观察,但这种方式不仅效率低…...
openEuler24.03 LTS下安装Hive3
目录 前提条件 安装MySQL 卸载原有mysql及mariadb 下载mysql 解压mysql 安装mysql 启动mysql服务 开机自启动mysql服务 登录mysql 修改mysql密码 远程连接mysql 安装Hive 下载安装包 解压 设置环境变量 解决日志包冲突 将mysql驱动拷贝到lib目录 配置Hive 创…...
13-动态规划-最长公共子序列
题目 来源 24. 最长公共子序列 思路 不想打字,援引自最长公共子序列 (LCS) 详解例题模板(全)-CSDN博客 图示举例: 其余详见代码 代码 #include<bits/stdc.h> using namespace std; const int N110; int f[N][N]; int m…...
golang 生成单元测试报告
在 Go 语言中,你可以使用 go test 生成单元测试报告。以下是几种方法: 1. 生成基本测试报告(文本格式) go test -v ./... > test_report.txt-v:显示详细的测试信息./...:递归测试所有子目录> test_r…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
设备健康管理系统是什么,设备健康管理系统多少钱?
想象一下,你的汽车在仪表盘报警前 3 天,手机就收到 “发动机轴承剩余寿命 1500 公里” 的提醒 —— 这就是 ** 设备健康管理系统(EHM)** 的日常。在制造业,设备故障每年造成全球 3.4 万亿美元损失,而 80% 的…...
设计模式(创建型)-抽象工厂模式
摘要 在软件开发的复杂世界中,设计模式作为解决常见问题的最佳实践方案,一直扮演着至关重要的角色。抽象工厂模式,作为一种强大的创建型设计模式,在处理创建一系列或相关依赖对象的场景时,展现出了独特的优势和灵活性。它通过提供一个创建对象的接口,让开发者能够在不指定…...
docker 部署elk 设置账号密码
1. 先把 kibana 停掉 2.进入es 容器 docker exec -it 75895a078cbc /bin/bash 找到 bin 目录 执行 ./elasticsearch-setup-passwords interactive 全部设置一样的密码 ,不一样自己要记住,设置成功会输出如下内容 Changed password for user [apm_system] Chang…...
<table>内有两行<tr>,第一行设定高度为60,剩余第二行,和右侧元素高度补齐。
实现 <table> 内第一行高度设定为 60px,第二行和右侧元素高度补齐的效果,你可以通过 CSS 样式来控制。示例: 为第一行 <tr> 设置固定高度 60px。对于右侧元素,假设它是一个 <div> 或者其他容器,将其…...
QT5.15.2加载pdf为QGraphicsScene的背景
5.15.2使用pdf 必须要安装QT源码,可以看到编译器lib目录已经有pdf相关的lib文件,d是debug 1.找到源码目录:D:\soft\QT\5.15.2\Src\qtwebengine\include 复制这两个文件夹到编译器的包含目录中:D:\soft\QT\5.15.2\msvc2019_64\include 2.找…...
常见的工具和技术
Mockito Mockito 是一个流行的 Java Mocking 框架,用于创建和配置模拟对象(Mock Objects),以便在单元测试中模拟复杂依赖关系的行为 使用场景:单元测试、隔离测试 EclipseEclipse 是一个开源的集成开发环境(…...
Linux怎样源码安装Nginx
1. 安装必要的依赖 在编译 Nginx 之前,你需要安装一些必要的依赖包,像编译工具和库文件等。以 CentOS 系统为例,可借助yum命令来安装: bash sudo yum install -y gcc pcre-devel zlib-devel openssl-devel要是使用的是 Ubuntu 系…...
汇编指令(20250319)
SOC常用总线 AHB(Advanced High-performance Bus):先进高性能总线,连接RAM,ROM等高速设备APB(Advanced Peripheral Bus):先进外设总线,连接外设等一些低速设备 CISC和R…...
PlainUSR|LIA: 追求更快的卷积网络实现高效的超分辨率重建
PlainUSR|LIA: 追求更快的卷积网络实现高效的超分辨率重建 引言 在深度学习领域,图像处理始终是一个热门话题。而超分辨率重建(Super-Resolution Reconstruction, SR)作为其中一个重要的研究方向,旨在通过算法将低分辨率图像恢复…...
神经网络基础之正则化
引言:正则化 (Regularization) 是机器学习中一种用于防止模型过拟合技术。核心思想是通过在模型损失函数中添加一个惩罚项 (Penalty Term),对模型的复杂度进行约束,从而提升模型在新数据上的泛化…...
JAVA序列化与反序列化URLDNS链CC1链
1、序列化的实现 java序列化的是对象属性的,只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常),静态成员变量是属于类的,所以静态成员变量是不能被序列化的&#x…...
孤儿进程和僵尸进程
本文讲述了什么是孤儿进程和僵尸进程,会带来怎样的问题以及如何处理 一、孤儿进程 1)什么是孤儿进程 孤儿进程,顾名思义,就是父进程提前终止,但是子进程还在运行中,父进程无法对子进程进行监管&#…...
用ASCII字符转化图片
代码 from PIL import Image# 定义 ASCII 字符集,从最暗到最亮 ASCII_CHARS "%#*-:. "def resize_image(image, new_width100):width, height image.sizeratio height / widthnew_height int(new_width * ratio)resized_image image.resize((new_wi…...
从WebRTC到嵌入式:EasyRTC如何借助大模型提升音视频通信体验
随着人工智能技术的快速发展,WebRTC与大模型的结合正在为音视频通信领域带来革命性的变革。WebRTC作为一种开源实时通信技术,以其低延迟、跨平台兼容性和强大的音视频处理能力,成为智能硬件和物联网设备的重要技术支撑。 而EasyRTC作为基于W…...
自动化测试工具-Playwright介绍和快速实例
Playwright 是什么 Playwright 是由 Microsoft 开发的开源自动化测试工具,专为现代 Web 应用设计。它支持 Chromium、Firefox 和 WebKit 内核的浏览器,能够跨平台(Windows、macOS、Linux)运行,提供强大的浏览器自动化能力,适用于测试、爬虫和监控等场景。 Playwright的…...
Java:Apache HttpClient中HttpRoute用法的介绍
当使用Apache HttpClient组件时,经常会用到它的连接池组件。典型的代码如下: PoolingHttpClientConnectionManager connectionManager new PoolingHttpClientConnectionManager();connectionManager.setMaxTotal(httpConfig.getMaxPoolTotal());connect…...
万字长文详解|蚂蚁数据湖深度探索与业务应用实践
作者介绍:黄超傑,蚂蚁数据智能部实时数据团队数据研发工程师,致力于数据湖技术在蚂蚁落地应用、蚂蚁广告实时数仓建设、蚂蚁数据成本治理等工作。 在开始之前 如果: 你想要提升数据时效,能够接受分钟级延迟你好奇准实…...
rk3568 以太网eth1 , 定制板 phy调试问题。
问题: 客户定制底板的 phy 网络不通。 解决逻辑: phy 问题, 就是 照着 公司底板对硬件就行,完全是硬件问题,不用改 软件。 原理图如下:...
React相关面试题
以下是150道React面试题及其详细回答,涵盖了React的基础知识、组件、状态管理、路由、性能优化等多个方面,每道题目都尽量详细且简单易懂: React基础概念类 1. 什么是React? React是一个用于构建用户界面的JavaScript库ÿ…...