Linux利用多线程和线程同步实现一个简单的聊天服务器
1. 概述
本文实现一个基于TCP/IP的简单多人聊天室程序。它包含一个服务器端和一个客户端:服务器能够接收多个客户端的连接,并将任何一个客户端发来的消息广播给所有其他连接的客户端;客户端则可以连接到服务器,发送消息并接收来自其他人的消息。该Demo运用了网络编程(Socket API)、多线程(Pthreads)以及线程同步(互斥锁)技术,以实现并发处理和数据共享安全。
2. 核心技术
-
网络编程(Sockets)
- TCP/IP: 选择面向连接的TCP协议,保证数据传输的可靠性。
- 服务器端流程:
socket()
: 创建套接字。memset()
/struct sockaddr_in
: 配置服务器地址和端口。bind()
: 绑定套接字到指定地址和端口。listen()
: 设置套接字为监听状态,等待连接。accept()
: 接受客户端连接,为每个连接创建一个新的套接字。
- 客户端流程:
socket()
: 创建套接字。memset()
/struct sockaddr_in
: 配置服务器地址和端口。connect()
: 连接到服务器。
- 数据传输:
read()
和write()
用于双向通信。
-
多线程 (Pthreads)
- 服务器端:
- 主线程负责
accept()
连接。 - 每接受一个新客户端,使用
pthread_create()
创建一个新的处理线程 (handle_clnt
)。 - 使用
pthread_detach()
将子线程设置为分离状态,使其结束后资源能自动回收,主线程无需join
。
- 主线程负责
- 客户端:
- 创建两个核心线程:
send_msg
线程:负责获取用户键盘输入并将其发送到服务器。recv_msg
线程:负责接收服务器广播的消息并显示在控制台。
- 这种设计使得用户输入和消息接收可以并行进行,互不阻塞。
- 创建两个核心线程:
- 服务器端:
-
线程同步 (Mutex)
- 场景: 服务器端多个
handle_clnt
线程会并发访问和修改共享资源(如客户端套接字数组clnt_socks
和当前客户端计数clnt_cnt
)。 - 机制: 使用互斥锁 (
mutx
) 保护这些临界区。pthread_mutex_init()
: 初始化互斥锁。pthread_mutex_lock()
: 在访问共享资源前加锁。pthread_mutex_unlock()
: 访问完毕后解锁。
- 关键操作加锁:
- 添加新客户端到
clnt_socks
。 - 从
clnt_socks
移除断开连接的客户端。 send_msg
(服务器端广播函数) 遍历clnt_socks
时。
- 添加新客户端到
- 场景: 服务器端多个
3. 主要模块实现
A. 服务器端 (server
)
main()
函数:- 参数解析 (端口号)。
- 初始化互斥锁。
- 完成socket的创建、绑定、监听。
- 进入无限循环,通过
accept()
接收客户端连接。 - 为每个连接创建
handle_clnt
线程并分离。
handle_clnt(void* arg)
函数:- 获取传递过来的客户端套接字。
- 循环调用
read()
接收该客户端的消息。 - 若
read()
成功,则调用send_msg()
(服务器的) 广播此消息。 - 若
read()
返回0 (客户端关闭连接),则执行清理:加锁 -> 从clnt_socks
移除 ->clnt_cnt--
-> 解锁 ->close()
该客户端套接字。
send_msg(char* msg, int len)
函数 (服务器端):- 加锁。
- 遍历
clnt_socks
数组,将消息write()
给每一个已连接的客户端。 - 解锁。
B. 客户端 (client
)
main()
函数:- 参数解析 (服务器IP, 端口号, 用户名)。
- 创建socket并
connect()
到服务器。 - 创建
send_msg
和recv_msg
两个线程。 pthread_join()
等待这两个线程结束(虽然当前send_msg
中的exit(0)
会提前终止)。
send_msg(void* arg)
函数:- 循环获取用户标准输入 (
fgets
)。 - 检测到 "q" 或 "Q" 时,
close(sock)
并exit(0)
(可改进点)。 - 将用户名和消息格式化后通过
write()
发送给服务器。
- 循环获取用户标准输入 (
recv_msg(void* arg)
函数:- 循环调用
read()
从服务器接收消息。 - 将接收到的消息
fputs()
到标准输出。
- 循环调用
4. 总结
- 互斥锁的必要性: 在多线程环境下,若不使用同步机制保护共享数据,会导致数据竞争和不可预期的结果。
clnt_socks
和clnt_cnt
的并发修改是典型场景。 - 线程分离 vs. 等待: 服务器端
pthread_detach
的使用简化了主线程的管理,适用于这种“即发即忘”的独立工作单元。客户端pthread_join
的意图是等待线程完成,但需配合更优雅的线程退出信号。 - 阻塞I/O与多线程: 每个客户端一个线程,每个线程中的
read()
是阻塞的。这简化了单个线程的逻辑,但当连接数非常大时,线程资源开销会成为瓶颈。 - 客户端非阻塞体验: 通过发送和接收分离到不同线程,客户端用户体验得到了提升,不会因为等待网络消息而卡住输入。
- 基本通信协议: 客户端在发送消息前简单地将用户名预置到消息体中,服务器直接转发这个消息体。这是一个非常初级的“协议”。
具体代码如下:
服务端代码:网络编程 + 多线程 + 线程同步
// 网络编程+多线程+线程同步实现的聊天服务器和客户端#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>#define BUF_SIZE 100 // 定义缓冲区大小
#define MAX_CLNT 256 // 最大客户端数量// 函数声明
void * handle_clnt(void * arg); // 处理客户端连接的线程函数
void send_msg(char * msg, int len); // 向所有客户端发送消息
void error_handling(char * msg); // 错误处理函数int clnt_cnt = 0; // 当前客户端连接数量
int clnt_socks[MAX_CLNT]; // 存储所有客户端的socket描述符
pthread_mutex_t mutx; // 互斥锁,用于同步对共享资源的访问(客户端数组)int main(int argc, char *argv[])
{int serv_sock, clnt_sock; // 服务端socket和客户端socketstruct sockaddr_in serv_adr, clnt_adr; // 服务端和客户端地址int clnt_adr_sz; // 客户端地址结构的大小pthread_t t_id; // 线程IDif(argc != 2) {printf("Usage : %s <port>\n", argv[0]); // 检查输入的端口号参数exit(1);}pthread_mutex_init(&mutx, NULL); // 初始化互斥锁serv_sock = socket(PF_INET, SOCK_STREAM, 0); // 创建服务端socketif(serv_sock == -1) {error_handling("socket() error");}memset(&serv_adr, 0, sizeof(serv_adr)); // 初始化服务端地址结构serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定到所有可用接口serv_adr.sin_port = htons(atoi(argv[1])); // 使用命令行提供的端口号if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1) // 绑定服务端socketerror_handling("bind() error");if(listen(serv_sock, 5) == -1) // 开始监听error_handling("listen() error");while(1){clnt_adr_sz = sizeof(clnt_adr); // 获取客户端地址大小clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz); // 接受客户端连接// 添加新的客户端socket到数组pthread_mutex_lock(&mutx); // 获取互斥锁,确保线程安全clnt_socks[clnt_cnt++] = clnt_sock; // 增加客户端到客户端数组pthread_mutex_unlock(&mutx); // 释放互斥锁// 创建新线程来处理客户端pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);pthread_detach(t_id); // 将线程分离,避免主线程等待printf("Connected client IP: %s \n", inet_ntoa(clnt_adr.sin_addr)); // 输出客户端IP地址}close(serv_sock); // 关闭服务端socketreturn 0;}// 处理客户端的函数
void * handle_clnt(void * arg)
{int clnt_sock = *((int*)arg); // 获取客户端socketint str_len = 0, i;char msg[BUF_SIZE]; // 缓冲区while((str_len = read(clnt_sock, msg, sizeof(msg))) != 0) // 读取客户端发送的消息send_msg(msg, str_len); // 将消息转发给所有客户端// 客户端断开连接后,移除客户端pthread_mutex_lock(&mutx); // 获取互斥锁for(i = 0; i < clnt_cnt; i++) // 查找并移除断开的客户端{if(clnt_sock == clnt_socks[i]){while(i++ < clnt_cnt - 1) // 将后续客户端前移clnt_socks[i] = clnt_socks[i + 1];break;}}clnt_cnt--; // 客户端数量减一pthread_mutex_unlock(&mutx); // 释放互斥锁close(clnt_sock); // 关闭客户端socketreturn NULL;}// 向所有客户端发送消息
void send_msg(char * msg, int len)
{int i;pthread_mutex_lock(&mutx); // 获取互斥锁,保护共享资源(客户端socket数组)for(i = 0; i < clnt_cnt; i++) // 向所有连接的客户端发送消息write(clnt_socks[i], msg, len);pthread_mutex_unlock(&mutx); // 释放互斥锁
}// 错误处理函数
void error_handling(char * msg)
{fputs(msg, stderr); // 输出错误信息fputc('\n', stderr);exit(1); // 退出程序
}
客户端代码:网络编程 + 多线程
// 客户端程序:网络编程+多线程实现的聊天客户端#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>#define BUF_SIZE 100 // 定义消息的最大长度
#define NAME_SIZE 20 // 定义用户名的最大长度// 函数声明
void * send_msg(void * arg); // 发送消息的线程函数
void * recv_msg(void * arg); // 接收消息的线程函数
void error_handling(char * msg); // 错误处理函数// 用户名和消息缓冲区
char name[NAME_SIZE] = "[DEFAULT]"; // 默认用户名
char msg[BUF_SIZE]; // 用于存储用户输入的消息int main(int argc, char *argv[])
{int sock;struct sockaddr_in serv_addr; // 服务器地址结构pthread_t snd_thread, rcv_thread; // 发送和接收消息的线程void * thread_return;// 检查命令行参数,确保提供了 IP、端口和用户名if(argc != 4) {printf("Usage : %s <IP> <port> <name>\n", argv[0]);exit(1);}// 设置客户端用户名sprintf(name, "[%s]", argv[3]);// 创建客户端socketsock = socket(PF_INET, SOCK_STREAM, 0);// 初始化服务器地址结构memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr(argv[1]); // 获取服务器的IP地址serv_addr.sin_port = htons(atoi(argv[2])); // 获取服务器的端口号// 连接到服务器if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)error_handling("connect() error");// 创建发送和接收消息的线程pthread_create(&snd_thread, NULL, send_msg, (void*)&sock);pthread_create(&rcv_thread, NULL, recv_msg, (void*)&sock);// 等待两个线程结束pthread_join(snd_thread, &thread_return);pthread_join(rcv_thread, &thread_return);close(sock); // 关闭客户端socketreturn 0;}// 发送消息的线程函数
void * send_msg(void * arg)
{int sock = *((int*)arg); // 获取客户端socketchar name_msg[NAME_SIZE + BUF_SIZE]; // 用于存储带有用户名的消息while(1) {fgets(msg, BUF_SIZE, stdin); // 获取用户输入的消息// 如果输入为 "q" 或 "Q",则退出程序if(!strcmp(msg, "q\n") || !strcmp(msg, "Q\n")) {close(sock); // 关闭socket连接exit(0); // 退出程序}// 将用户名和消息合并成一个字符串sprintf(name_msg, "%s %s", name, msg);// 发送合并后的消息到服务器write(sock, name_msg, strlen(name_msg));}return NULL; // 返回空值}// 接收消息的线程函数
void * recv_msg(void * arg)
{int sock = *((int*)arg); // 获取客户端socketchar name_msg[NAME_SIZE + BUF_SIZE]; // 用于存储带有用户名的消息int str_len;while(1){// 从服务器读取消息str_len = read(sock, name_msg, NAME_SIZE + BUF_SIZE - 1);if(str_len == -1) // 如果读取失败,返回错误return (void*)-1;name_msg[str_len] = 0; // 将读取的字符串以 null 结尾fputs(name_msg, stdout); // 输出服务器发来的消息}return NULL; // 返回空值}// 错误处理函数
void error_handling(char *msg)
{fputs(msg, stderr); // 将错误消息输出到标准错误fputc('\n', stderr); // 输出换行符exit(1); // 退出程序
}
相关文章:
Linux利用多线程和线程同步实现一个简单的聊天服务器
1. 概述 本文实现一个基于TCP/IP的简单多人聊天室程序。它包含一个服务器端和一个客户端:服务器能够接收多个客户端的连接,并将任何一个客户端发来的消息广播给所有其他连接的客户端;客户端则可以连接到服务器,发送消息并接收来自…...
无人机遥控器光纤通信模块技术要点!
一、技术要点 1. 长距离低损耗传输 采用单模光纤(如G.654.E光纤),利用光纤的低衰减特性(0.17 dB/km以下),支持10公里以上的远距离通信,突破了传统无线信号因衰减导致的覆盖限制。例如&…...
深入解析OkHttp与Retrofit:Android网络请求的黄金组合
前言 在移动应用开发中,网络请求是连接客户端与服务器的关键桥梁。对于Android开发者而言,OkHttp和Retrofit这对组合已经成为处理网络请求的事实标准。本文将全面剖析这两个框架的设计理念、核心功能、协同关系以及最佳实践,帮助开发者构建高…...
Python操作PDF书签详解 - 添加、修改、提取和删除
目录 简介 使用工具 Python 向 PDF 添加书签 添加书签 添加嵌套书签 Python 修改 PDF 书签 Python 展开或折叠 PDF 书签 Python 提取 PDF 书签 Python 删除 PDF 书签 简介 PDF 书签是 PDF 文件中的导航工具,通常包含一个标题和一个跳转位置(如…...
Spring Boot与Kafka集成实践:从入门到实战
Spring Boot与Kafka集成实践 引言 在现代分布式系统中,消息队列是不可或缺的组件之一。Apache Kafka作为一种高吞吐量的分布式消息系统,广泛应用于日志收集、流处理、事件驱动架构等场景。Spring Boot作为Java生态中最流行的微服务框架,提供…...
luckysheet的使用——17.将表格作为pdf下载到本地
luckysheet源码里面自带有打印按钮,但是功能是无法使用的,所以我把该功能重写了一遍 1.在menuButton.js文件中找到源码打印按钮的触发事件: $("#luckysheet-icon-print").click(function () {}2.使用自己写的挂载方法 window.pr…...
矿井支架LCYVB-6钢丝编织护套连接器介绍
LCYVB-6钢丝编织护套连接器是一种专为矿井支架设计的连接装置,主要用于增强支架的稳定性和安全性。该连接器采用高强度钢丝编织护套,具有优异的抗拉强度和耐磨性,适用于恶劣的矿井环境。 主要特点 高强度钢丝编织护套:采用优质钢…...
git仓库中.git 文件很大,怎么清理掉一部分
查询 .git 文件大小,在 git-bash 里执行(后面有些命令不能执行,也请在 git-bash 里执行) windows11 安装好后右键没有 git bash 命令-CSDN博客 du -sh .git // 592m .git 操作前最好先备份一份,避免推送到远程时出错…...
Qt框架核心组件完全指南:从按钮交互到定时器实现
文章目录 前言一、QAbstractButton 按钮类概述1.1 常用属性1.2 常用信号1.3QButtonGroup 按钮组 二、QComboBox 组合框三、若干与数字相关的组件四、QString 字符串类五、Qt容器类5.1 顺序容器 QList5.2 关联容器 QMap 六、QVariant七、跨平台数据类型7.1 基础数据类型7.2 特殊…...
Axure设计数字乡村可视化大屏:从布局到交互的实战经验分享
乡村治理正从传统模式向“数据驱动”转型。数字乡村可视化大屏作为数据展示的核心载体,不仅能直观呈现乡村发展全貌,还能为决策提供科学依据。本文以Axure为工具,结合实际案例,分享如何从零设计一个功能完备、交互流畅的数字乡村大…...
60天python训练计划----day30
DAY 30 模块和库的导入 知识点回顾: 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) 一.导入官方库 我们复盘下学习python的逻辑,所谓学习pyth…...
HJ3 明明的随机数【牛客网】
文章目录 零、原题链接一、题目描述二、测试用例三、解题思路3.1 快排去重3.2 散列 四、参考代码4.1 快排去重4.2 散列 零、原题链接 HJ3 明明的随机数 一、题目描述 二、测试用例 三、解题思路 3.1 快排去重 基本思路: 先将序列进行快速排序,然后…...
BGP选路
一、拓扑图 二、要求及分析 1.要求 1.使用Preva1策略,确保R4通过R2到达192.168.10.0/24 2、用As Path策略,确保R4通过R3到达192.168.11.0/24 3.配置MED策略,确保R4通过R3到达192.168.12.0/24 4.使用Local Preference策略,确保…...
践行“科学智能”!和鲸打造 AI for Science 专属应用
AI for good, AI for Science. 在传统科研领域,人力与经验的局限始终如影随形。而“AI for Science”正逐渐改变科学研究的模式,以科学数据为基石、以强大算力为支撑,借助人工智能技术,开展计算密集度高且能够实现高效迭代的科学…...
【vs2022的C#窗体项目】打开运行+sql Server改为mysql数据库+发布
1. vs2022打开运行原sql Server的C#窗体项目更改为mysql数据库 1.1. vs2022安装基础模块即可 安装1️⃣vs核心编辑器2️⃣.net桌面开发必选,可选均不安装!!! 为了成功连接mysql数据库,需要安装组件NuGet包管理器 安…...
wpf DataGrid 行选择事件
在WPF中处理DataGrid行选择事件主要有以下几种实现方式: 1.SelectionChanged事件处理 通过直接订阅DataGrid的SelectionChanged事件实现行选择响应: <DataGrid SelectionChanged="DataGridAccurateLocationList_SelectionChanged" .../>后台代码中处理…...
Spring Cloud Seata 深度解析:原理与架构设计
文章目录 前言:为什么我们需要理解分布式事务?一、Seata 核心架构深度拆解1.1 分布式事务核心模型1.2 Seata undo_log 存储结构与版本控制存储结构版本控制核心算法 1.3 Seata 事务模型深度对比与实现原理AT 模式(Auto Transaction࿰…...
从产品展示到工程设计:3DXML 转 STP 的跨流程数据转换技术解析
在数字化设计与制造领域,不同格式的三维模型文件常常需要进行转换,以满足不同软件和工作流程的需求。3DXML 和 STP(STEP AP214/AP242)是工业领域常用的两种三维模型文件格式,3DXML 格式以其轻量化和便于网络传输、可视…...
基于RT-Thread的STM32F4开发第五讲——软件模拟I2C
文章目录 前言一、RT-Thread工程创建二、AT24C02三、函数编写1.I2C_soft.c2.I2C_soft.h3.main.h 四、效果展示五、资源分享总结 前言 本章是基于RT-Thread studio实现软件模拟I2C,开发板是正点原子的STM32F4探索者,使用的RT-Thread驱动是5.1.0࿰…...
pkucpc2025 L:Game on Tree
题意 两个人在一棵无根树上玩游戏,每次可以删掉若干个叶子节点,不能操作的人输。 思路 比赛的时候我去写H Quintuple了,队友貌似在我写的时候把这道题讨论出来了。 后来补题的时候花了大概花了70分钟左右ac这道题。 首先考虑一条链的情况…...
大数据实时分析:ClickHouse、Doris、TiDB 对比分析
随着企业对数据分析实时性、复杂性和多样性的要求越来越高,传统的批处理数仓已经无法满足实时指标看板、流量监控、用户行为分析等场景需求。因此,越来越多的公司开始引入实时分析型数据库系统。 目前,国内外常见的实时分析数据库有: ClickHouse:列式数据库,极致的分析性…...
网络流量分析系统的十大应用场景
在现代企业和组织的IT运维体系中,网络流量分析系统(Network Traffic Analysis, NTA)早已不仅仅是用来查看带宽使用率的“流量计数器”。随着网络环境的复杂化、攻击技术的不断演进,以及对业务连续性要求的提升,网络流量…...
问题 | 代码审查:函数是否包含返回语句
“函数是否包含返回语句”这一问题的核心是:在编程中,函数是否按照设计要求正确使用了 返回语句(如 return、return value),以便向调用者传递结果或控制权。以下是详细解释: 1. 什么是函数的返回语句&#…...
Spring Bean 生命周期中设计模式的应用与解析
Spring Bean 生命周期中使用的设计模式 Spring Bean 的生命周期涉及多个阶段和扩展点,Spring 框架在这一过程中巧妙运用了多种设计模式,以实现强大的功能和灵活性。以下是主要设计模式及其应用场景: 1. 工厂模式(Factory Patter…...
设计模式的原理及深入解析
创建型模式 创建型模式主要关注对象的创建过程,旨在通过不同的方式创建对象,以满足不同的需求。 工厂方法模式 定义:定义一个创建对象的接口,让子类决定实例化哪一个类。 解释:工厂方法模式通过定义一个创建对象的…...
kotlin flow的两种SharingStarted策略的区别
一 两种 SharingStarted 策略的区别: SharingStarted.Eagerly: 立即开始收集上游流,即使没有下游订阅者持续保持活跃状态,直到 ViewModel 被清除优点:响应更快,数据始终保持最新缺点:消耗更多资源&#x…...
BGP综合实验(2)
一、实验需求 1、实验拓扑图 2、实验需求 使用 PreVal 策略,让 R4 经 R2 到达 192.168.10.0/24 。 使用 AS_Path 策略,让 R4 经 R3 到达 192.168.11.0/24 。 配置 MED 策略,让 R4 经 R3 到达 192.168.12.0/24 。 使用 Local Preference 策…...
python使用jsonpath-ng库操作json数据
jsonpath-ng 库的详细使用如下: 一、安装与导入 安装 通过 pip 安装库: pip install jsonpath-ng支持 Python 3.6 及以上版本。 导入核心模块 主要使用 parse 函数和 JSONPath 对象: from jsonpath_ng import parse二、基础查询操作 1. 简单…...
通用简洁工作汇报项目评估营销策划工作总结年终汇报PPT模版8套一组分享
工作总结汇报PPT模版8套一组分享:工作总结汇报PPT模版分享https://pan.quark.cn/s/04b7ab7a47c4 第一套PPT模版,主要是黄色和灰色调,上方有大面积黄色不规则形状背景,有“POWERPOINT”和“XXXXPPT模版”字样,左侧是黑…...
掌握Git:版本控制与高效协作指南
一、初始Git 提出问题:无论是在工作还是学习,我们在编写各种文档的时候,更改失误,失误后恢复到原来版本,不得不复制出一个副本。 每个版本由各自的内容,但最终只有一个报告需要被我们使用。 但在此之前的…...
ubuntu下配置vscode生成c_cpp_properties.json
-------------学习记录--------------- 在ubuntu下使用vscode时发现cpp文件无法读到头文件,明明头文件在合适的路径下,由于没有制定头文件的路径造成的这个问题。用这篇文章进行简单记录解决方法 ctrlshiftp打开命令面板,也可以点击左上角, …...
Qt读取Excel文件的技术实现与最佳实践
目录 一、成果展示二、核心方法及原理1. QAxObject(基于COM接口)2. 第三方库QXlsx3. ODBC数据库驱动 三、实现步骤详解1. QAxObject读取Excel(需安装Excel/WPS)2. QXlsx读取Excel(跨平台方案) 四、技术选型…...
双条件拆分工作表,一键生成独立工作簿-Excel易用宝
你是否遇到过这样的崩溃瞬间?面对一张密密麻麻的销售数据表,需要按指定维度拆分成工作簿和工作表,而你却只能手动复制粘贴到不同工作簿、工作表,改一个字段就花半小时,数据量大时甚至要熬夜加班? 别担心&a…...
iOS 蓝牙开发中的 BT 与 BLE
在 iOS 开发者的语境里,大家把 BT 和 BLE 当成两种不同的蓝牙技术在谈——它们来自同一个 Bluetooth 规范,但面向的场景、协议栈乃至 Apple 提供的 API 都截然不同。 缩写全称 / 技术名称规范层叫法iOS 支持现状典型用途BTBluetooth Classic(经典蓝牙)又叫 BR/EDR(Basic R…...
TCP和套接字SSL加密连接行为分析
目录 一、前言 二、背景 三、参数介绍 3.1、 have_openssl 3.2、have_ssl 3.3、require_secure_transport 四、--ssl-modemode 五、CREATE USER SSL/TLS选项 六、问题验证 6.1、使用套接字连接 6.2、使用TCP连接 七、分析与总结 一、前言 SSL(Secure S…...
kafka 问与答
kafka Q&A How does the client connect to kafka and discovery the brokers. client 只需要知道一部分nodes(brokers)的地址既可以,client 会自动发现剩下的所有topic partition leader nodes, 然后连接上。 When a client connects:It uses the bootstrap…...
docker默认存储迁移
在容器化场景下默认存储路径为(/var/lib/docker)大多数平台根目录不支持系统盘扩容,会有空间不足风险隐患,因未配置持久化存储导致容器数据丢失。以迁移Docker存储路径至大容量/data目录说明 一、停止容器 systemctl stop docke…...
Ubuntu20.04系统下使用交叉编译工具链(aarch、x86)交叉编译opencv4.5.0
文章目录 0. 引言1. 准备交叉编译工具链2. 安装依赖工具3. 下载 OpenCV 源码4. 创建交叉编译工具链文件5. 配置 CMake 构建6. 构建 OpenCV7. 安装 OpenCV8. 验证9. 问题及解决办法 0. 引言 Ubuntu20.04系统下使用交叉编译工具链(aarch、x86)交叉编译ope…...
R语言数据可视化
R note book 文档–输出html格式文档,plotly不能生成PDF文件 --- title: "R语言数据可视化" output: html_notebook ---在R语言中进行数据可视化是数据分析和呈现的重要环节,R提供了多种强大的绘图系统和工具。以下是常见的数据可视化方法和示…...
NLP学习路线图(一): 线性代数(矩阵运算、特征值分解等)
引言:语言与矩阵的奇妙邂逅 在自然语言处理(NLP)的魔法世界里,每个词语都像被施了变形术的精灵,在数学的殿堂中翩翩起舞。当我们用"king - man woman queen"这样的向量魔法破解语义密码时,线性…...
【滑动窗口】LeetCode 1004题解 | 最大连续1的个数 Ⅲ
最大连续1的个数 Ⅲ 一、题目链接二、题目三、题目解析四、算法原理解法一:暴力枚举 zero计数器解法二:滑动窗口 五、编写代码六、时空复杂度 一、题目链接 最大连续1的个数 Ⅲ 二、题目 三、题目解析 注意题目中说的是最多k次,在一个数组…...
Linux 内核等待机制详解:prepare_to_wait_exclusive 与 TASK_INTERRUPTIBLE
1. prepare_to_wait_exclusive 函数解析 1.1 核心作用 prepare_to_wait_exclusive 是 Linux 内核中用于将进程以独占方式加入等待队列的关键函数,其主要功能包括: 标记独占等待:通过设置 WQ_FLAG_EXCLUSIVE 标志,表明此等待条目是独占的。 安全入队:在自旋锁保护下,将条…...
分布式数据库TiDB:深度解析原理、优化与架构设计
💂 个人网站:【 摸鱼游戏】【神级代码资源网站】【星海网址导航】 一、TiDB架构设计与核心原理 1.1 分布式架构演进 传统分库分表 vs TiDB架构 #mermaid-svg-8I88Hg2AVkzYTb3O {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fi…...
【深度学习基础】损失函数与优化算法详解:从理论到实践
【深度学习基础】损失函数与优化算法详解:从理论到实践 一、引言 1. 损失函数与优化算法在深度学习中的核心作用 在深度学习中,模型训练的本质是通过不断调整参数,使模型输出尽可能接近真实值。这一过程的核心驱动力是损失函数(…...
睿抗足球机器人
目录 大框架 战术 Lua脚本语言编辑环境 大框架 策略脚本(LUA-官方脚本)、决策算法(C-自定义)、ROS系统 战术 我们研究了场地的长度、宽度、禁区范围、机器人运动速度等等,发现即使 Kicker 点球往极端角度踢…...
助力DBA技能无缝平迁 | YashanDB携最新成果亮相XCOPS智能运维管理人年会
5 月 16 日,由上海市软件行业协会、上海市计算机行业协会指导, dbaplus社群主办的XCOPS智能运维管理人年会在广州盛大召开,活动汇聚500余名金融、政府、能源、教育、电信、交通等领域的行业专家。深算院崖山数据库受邀参会,系统性…...
服务端安全测试:OWASP ZAP使用
ZAP下载地址:https://www.zaproxy.org/download/ ZAP有两种扫描方式: 1、使用 OpenAPI / Swagger 地址进行扫描 2、ZAP Proxy + Postman 因为业务云没有添加swagger插件所以本次介绍第2种方式。 【第一步】设置 ZAP 的代理端口(默认是 127.0.0.1:8080) 成功安装并打…...
Amazon Q 从入门到精通 – 测试与重构
Amazon Q Developer 是亚马逊推出的一个专为专业开发人员设计的人工智能助手,旨在提升代码开发和管理效率。其主要功能包括代码生成、调试、故障排除和安全漏洞扫描,提供一站式代码服务。 众所周知,在软件开发领域,测试代码是软件…...
[CSS3]属性增强2
空间转换 使用transform属性实现元素在空间内的位移、旋转、缩放等效果 空间: 是从坐标轴角度定义的。x、y 和z三条坐标轴构成了一个立体空间,z轴位置与视线方向相同。空间转换也叫3D转换 空间位移 使用translate实现元素空间位移效果 transform: translate3d(x…...
Go 语言 vs C+Lua(Skynet)游戏服务器方案对比分析
为啥挑这两个呢?因为两种技术分别对应CSP模型和Actor模型,都是经过时间检验的成熟且可靠的并发模型,问了很多地方,经过gpt整理得出如下报告。 从开发效率、运行性能、热更新扩展、云部署与水平扩展能力、多类型游戏支持等五个维度…...