5.10-套接字通信 - C++
套接字通信
1.1 通信效率问题
-
服务器端
-
单线程 / 单进程
- 无法使用,不支持多客户端
-
多线程 / 多进程
- 写程序优先考虑多线程:
- 什么时候考虑多进程?
- 启动了一个可执行程序 A ,要在 A 中启动一个可执行程序 B
- 支持多客户端连接
-
IO 多路转接
-
单线程 / 进程
-
支持多客户端连接但是效率不是最高的
- 所有的客户端请求都是顺序处理的 -> 排队
-
多线程
int main() {// 1. 监听 fdint lfd = socket(); };// 2. 绑定bind();// 3. 监听listen();// 4. 初始化 epoll()int epfd = epoll_create(x);// 5. epooll 添加检测节点 -> lfdepoll_ctl(epfd, epoll_ctl_add, lfd, &ev);while (1){int num = epoll_wait(epfd, evs, 1024, NULL);for (int i = 0; i < num; i++){if (curfd == lfd){pthread_create(&tid, NULL, acceptConn, &epfd);// accept();}else{...// read();// write();}}} }
-
线程池
-
多个线程的一个集合,可以回收用完的线程
- 线程池的个数取决于业务逻辑
-
密集型业务逻辑:需要大量 cpu 时间进行数据处理
- 线程个数 == 电脑核心数
-
进行 io 操作
- 线程个数 == 两倍 cpu 核心数
-
- 线程池的个数取决于业务逻辑
-
不需要重复频繁地创建销毁线程
-
设计思路
1. 需要两个角色- 管理者 -> 1 个- 工作的线程 -> N 个 2. 管理者- 不工作(不处理业务逻辑,监测工作的线程的状态,管理线程的个数)- 假设工作线程不够用了,动态创建新的线程- 假设工作的线程太多了,销毁一部分工作的线程- 动态监测工作的线程的状态 3. 工作的线程- 处理业务逻辑 4. 需要一个任务队列- 存储任务 -> 唤醒阻塞线程 -> 条件变量- 工作的线程处理任务队列中的任务- 没有任务 -> 阻塞
-
-
-
-
-
-
客户端
// 创建TcpSocket对象 == 一个连接,这个对象就可以和服务器通信了,多个连接需要创建多个这样的对象 class TcpSocket { public:TcpSocket(){m_connfd = socket(af_inet, sock_stream, 0);}TcpSocket(int fd){m_connfd = fd; // 传递进行的fd是可以直接通信的文件描述符,不需要连接操作}~TcpSocket();/* 客户端 连接服务器 */int conectToHost(string ip, unsigned short port, int connecttime){connect(m_connfd, &serverAddress, &len);}/* 客户端 关闭和服务端的连接 */int disConnect();/* 客户端 发送报文 */int sendMsg(string sendMsg, int sendtime = 10000){senf(m_connfd, data, datalen, 0);}/* 客户端 接受报文 */string recvMsg(int timeout){recv(m_connfd, buffer, size, 0);return buffer;}private:int m_connfd; };
-
服务器
// 思想: 服务端不负责通信,只负责监听,如果通信使用客户端类 class TcpServer { public:// 初始化监听的套接字: 创建,绑定,监听TcpServer();~TcpServer(); // 在这里边关闭监听的fdTcpSocket* acceptConn(int timeout = 999999){int fd = accept(m_lfd, &address, &len);// 通信fd -> 类TcpSocket* tcp = new TcpSocket(fd);if (tcp != nullptr){return tcp;}return nullptr;}private:int m_lfd; // 监听的fd };
// 使用 void * callback(void* arg) {TcpSocket * tcp = (TcpSocket *) arg;tcp->sendMsg();tcp->recvMsg();tcp->disConnect();delete tcp; }int main() {TcpServer * server = new Tcpserver;while (1){TcpSocket * tcp = server->acceptConn();// 创建子进程 -> 通信pthread_create(&tid, NULL, callback, arg)}delete server;return 0; }
// 客户端程序 int main() {TcpSocket * tcp = new TcpSocket;tcp->ConnectToHost(ip, port, timeout);tcp->sendMsg();tcp->recvMsg();tcp->disConnect();delete tcp; }
2 套接字超时
套接字通信过程中的默认的阻塞函数
等待并接受客户端连接
通信、接受数据、发送数据、连接服务器时
设置超时处理的原因:不想让进程(线程)一直在对应为止阻塞
超时处理的思路:
- 定时器
sleep(10)
- 以上两种不可用,在指定时间内阻塞函数满足条件直接解除阻塞,以上两种不满足要求
- IO 多路转接函数
- 这些函数最后一个参数是设置阻塞的时长,如果有
fd
发生变化,函数直接返回- 帮助委托内核检测
fd
状态:读写异常
2.1 accept 超时
// 等待并接受客户端连接
// 如果没有客户端连接,一直阻塞
// 检测 accept 函数的 fd 读缓冲区就可以了
int accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen);// 使用select 函数检测状态
int select(int nfds, fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);
// 通信的fd放到 fd_set 中检测
if (ret == 0)
{// 超时
}
else if (ret == 1)
{// 有新连接accept(); // 绝对不阻塞
}
else
{// error, -1
}
读超时、写超时略
2.2 connect 超时
// 连接服务器 -> 处于连接过程中,函数不返回 -> 程序阻塞在这个函数上,可通过返回值判断是不是连接成功了
// 返回值 0,成功,-1,失败
// 该函数默认有一个超时处理:75s 或 175s- 设置 connect 函数操作的文件描述符为非阻塞- 使用 select 检测- 设置 connect 函数操作的文件描述符为阻塞 -> 状态还原
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);// 与上述同理
2.3 tcp 粘包问题
造成原因:
- 发送的时候,内核进行了优化,数据达到一定量发一次
- 网络环境不好,有延迟
- 接收方频率低,一次性读到了多条客户端发送的数据
解决方案:
- 发送的时候强制缓存区发送数据
- 在发送数据的时候添加包头
- 包头:一块内存,存储了当前消息的属性信息
- 属于谁:char[12]
- 有多大:int
- …
3 进程间通信:共享内存
-
使用流程
1. 向内核申请一块内存 -> 指定大小 2. 如果有两个进程需要进行通信,可以使用共享内存通信,先创建两个进程 3. 进程 A 和进程 B 分别和共享内存进程关联- 拿到共享内存的地址 -> 首地址 4. 两个进程可以公国这个首地址对共享内存进行读(写)操作 5. 如果这个进程不再使用这块共享内存,需要和共享内存断开连接- 进程退出对共享内存没有任何影响 6. 当不再使用共享内存的时候,需要将共享内存销毁
-
共享内存头文件
#include <sys/ipc.h> #include <sys/shm.h>
-
共享内存操作函数
-
创建或打开一块共享内存区
// 创建共享内存 // 共享内存已经存在 // 可以创建多块共享内存 int shmget(key_t key, size_t size, int sh mhflg);key:通过 key 记录共享内存在内核中的位置,为一个大于零的整数,等于 0 不行,随便指定一个就可以size:创建共享内存的时候指定共享内存的大小。如果已经创建,设为 0shmflg:创建共享内存的时候使用,指定打开文件的方式 返回值:成功:创建(打开)成功,得到一个整形数失败:-1// 应用 // 1. 创建共享内存 int shmid = shmget(100, 4096, IPC_CREAT | 0664); int shmid = shmget(200, 4096, IPC_CREAT | 0664); // 2. open share memory int shmid = shmget(100, 0, 0)
-
将当前进程与共享内存关联
void * shmat(int shmid, const void * shmaddr, int shmflg);参数:- shmid:通过这个参数访问共享内存,shmget() 的返回值- shmaddr:指定共享内存在内核中的位置,指定为空,委托内核寻找- shmflg:关联成功后对内存的操作权限- SHM_RDONLY:只读- 0:读写 成功:内存的地址 失败:(void *)-1// 函数调用: shmat(shmid, NULL, 0); // write on shm memcpy(ptr, "xxx", len); printf("%s", (char*)ptr);
-
depart shm
int shmdt(const void * shmaddr);arg: address of shmreturn:suc: 0fai: -1
-
control shm
int shmctl(int shmid, int com, struct shmid_ds * buf);arg:-shimd: reuturn value of shmget- cmd: operation to shm- IPC_STAT: get status of cmd- IPC_SET: set shm- IPC_RMID: mark shm to be destroyed- buf: as a struct can describe the status of shm reutrn value:succ: 0fail: -1// demo: destroy shm shmctl(shmid, IPC_RMID, nullptr);
demo: communication of processes
read:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h>int main() {// 1. open shmint shmid = shmget(100, 0, 0);// 2. relate shm with cur processvoid* ptr = shmat(shmid, NULL, 0);// 3. write on shmprintf("content: %s\n", (char *)ptr);printf("press any key to continue ...\n");getchar();// 4. release relevanceshmdt(ptr);// 5. destory shmshmctl(shmid, IPC_RMID, NULL);return 0; }
write:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h>int main() {// 1. create shmint shmid = shmget(100, 4096, IPC_CREAT|0664);// 2. relate shm with cur processvoid* ptr = shmat(shmid, NULL, 0);// 3. write on shmconst char * tmp = "this is a damo for shm ...";memcpy(ptr, tmp, strlen(tmp) + 1);printf("press any key to continue ...\n");getchar();// 4. release relevanceshmdt(ptr);// 5. destory shmshmctl(shmid, IPC_RMID, NULL);return 0; }
-
-
question:
- question 1: how dose the operation system know the number of process that relate with a shm?
- shm keep a struct
struct shmid_ds
, that has a membershm_nattch
. shm_nattch
records the number of being related process.
- shm keep a struct
- question 2: whether can call
shmctl
to destroyed a shm more than once?- yes
- because
shmctl
function is just marking a shm to be destroy, not destroying it directly. - when it was destroyed truly?
- when
shm_nattch == 0
- when
the commands to observe the shm:
ipcs -m
-
ftok
function prototypekey_t ftok(const char *pathname, int proj_id);- pathname: the absolute path- proj_id: only use the top 1 byte- value range: 1 - 255key_t t = fotk("/home/", 'a');
-
difference of shm and mmp
. . .
4 the API encapsulation of shm
class BashShm
{
public:BashShm(int key); // open a shm according a given key.BashShm(string path); // **with no size**, according to string path -> int key, open a shm.BashShm(int key, int size); // create a shm by the given key and size.BashShm(string path, int size); // string -> key, according to size.void * mapshm(){m_ptr = shmat(shmid);return shmat();}int unmapshm(){return shmdt(m_ptr);}int delshm(){return shmctl(shmid);}private:int m_shmid; // reuturn value of `shmat()`void * m_ptr
}
相关文章:
5.10-套接字通信 - C++
套接字通信 1.1 通信效率问题 服务器端 单线程 / 单进程 无法使用,不支持多客户端 多线程 / 多进程 写程序优先考虑多线程:什么时候考虑多进程? 启动了一个可执行程序 A ,要在 A 中启动一个可执行程序 B 支持多客户端连接 IO 多…...

suricata增加单元测试编译失败
一、环境 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Codename: jammysuricata: suricata7.0.5 IDE: vscode 二、背景 在suricata中开发了某个功能后,增加unittest时,…...

高并发场景下的BI架构设计:衡石分布式查询引擎与缓存分级策略
在电商大促、金融交易时段或IoT实时监控场景中,企业BI系统常面临瞬时万级并发查询的冲击——运营团队需要实时追踪GMV波动,风控部门需秒级响应欺诈检测,产线监控需毫秒级反馈设备状态。传统单体架构的BI系统在此类场景下极易崩溃,…...

鱼眼摄像头(一)多平面格式 单缓冲读取图像并显示
鱼眼摄像头(一)多平面格式 单缓冲读取图像并显示 1.摄像头格式 1. 单平面格式(Single Plane):各通道数据保存在同一个平面(缓冲),图像数据按行连续存储a. mjpeg,yuyv等…...

机器学习笔记——特征工程
大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本笔记介绍机器学习中常见的特征工程方法、正则化方法和简要介绍强化学习。 文章目录 特征工程(Fzeature Engineering)1. 特征提取ÿ…...

A Survey of Learning from Rewards:从训练到应用的全面剖析
A Survey of Learning from Rewards:从训练到应用的全面剖析 你知道大语言模型(LLMs)如何通过奖励学习变得更智能吗?这篇论文将带你深入探索。从克服预训练局限的新范式,到训练、推理各阶段的策略,再到广泛…...

Python爬虫第20节-使用 Selenium 爬取小米商城空调商品
目录 前言 一、 本文目标 二、环境准备 2.1 安装依赖 2.2 配置 ChromeDriver 三、小米商城页面结构分析 3.1 商品列表结构 3.2 分页结构 四、Selenium 自动化爬虫实现 4.1 脚本整体结构 4.2 代码实现 五、关键技术详解 5.1 Selenium 启动与配置 5.2 页面等待与异…...
无线定位之 三 SX1302 网关源码 thread_gps 线程详解
前言 笔者计划通过无线定位系列文章、系统的描述 TDOA 无线定位和混合定位相关技术知识点, 并以实践来验证此定位系统精度。 笔者从实践出发、本篇直接走读无线定位系统关键节点、网关 SX1302 源码框架,并在源码走读过程 中、着重分析与无线定位相关的PPS时间的来龙去脉、并在…...

Aware和InitializingBean接口以及@Autowired注解失效分析
Aware 接口用于注入一些与容器相关信息,例如: a. BeanNameAware 注入 Bean 的名字 b. BeanFactoryAware 注入 BeanFactory 容器 c. ApplicationContextAware 注入 ApplicationContext 容器 d. EmbeddedValueResolverAware 注入 解析器&a…...

Unity3D仿星露谷物语开发41之创建池管理器
1、目标 在PersistentScene中创建池管理器(Pool Manager)。这将允许一个预制对象池被创建和重用。 在游戏中当鼠标点击地面时,便会启用某一个对象。比如点击地面,就创建了一棵树,而这棵树是从预制体对象池中获取的&a…...

Modbus协议介绍
Modbus是一种串行通信协议,由Modicon公司(现为施耐德电气)在1979年为可编程逻辑控制器(PLC)通信而开发。它是工业自动化领域最常用的通信协议之一,具有开放性、简单性和跨平台兼容性,广泛应用于…...
深度学习遇到的问题处理
小土堆课程学习 1.tensorboard远程到本地无法显示 1.检查本地与远程端口是否被占用 2.一定要在远程服务器的项目下创建对应的存储文件夹 且 远程服务器一定要有需要处理的数据 ## 此时远程项目路径下有logs文件夹 存放上传的图像与数据 writerSummaryWriter("logs"…...

I/O多路复用(select/poll/epoll)
通过一个进程来维护多个Socket,也就是I/O多路复用,是一种常见的并发编程技术,它允许单个线程或进程同时监视多个输入/输出(I/O)流(例如网络连接、文件描述符)。当任何一个I/O流准备好进行读写操…...

Westlake-Omni 情感端音频生成式输出模型
简述 github地址在 GitHub - xinchen-ai/Westlake-OmniContribute to xinchen-ai/Westlake-Omni development by creating an account on GitHub.https://github.com/xinchen-ai/Westlake-Omni Westlake-Omni 是由西湖心辰(xinchen-ai)开发的一个开源…...
Egg.js知识框架
一、Egg.js 核心概念 1. Egg.js 简介 基于 Koa 的企业级 Node.js 框架(阿里开源) 约定优于配置(Convention over Configuration) 插件化架构,内置多进程管理、日志、安全等能力 适合中大型企业应用,提供…...

随手记录5
一些顶级思维: 顶级思维 1、永远不要自卑。 也永远不要感觉自己比别人差,这个人有没有钱,有多少钱,其实跟你都没有关系。有很多人就是那个奴性太强,看到比自己优秀的人,甚至一些装逼的人,这…...

Linux驱动:驱动编译流程了解
要求 1、开发板中的linux的zImage必须是自己编译的 2、内核源码树,其实就是一个经过了配置编译之后的内核源码。 3、nfs挂载的rootfs,主机ubuntu中必须搭建一个nfs服务器。 内核源码树 解压 tar -jxvf x210kernel.tar.bz2 编译 make x210ii_qt_defconfigmakeCan’t use ‘…...

使用 Flowise 构建基于私有知识库的智能客服 Agent(图文教程)
使用 Flowise 构建基于私有知识库的智能客服 Agent(图文教程) 在构建 AI 客服时,常见的需求是让机器人基于企业自身的知识文档,提供准确可靠的答案。本文将手把手教你如何使用 Flowise + 向量数据库(如 Pinecone),构建一个结合 RAG(Retrieval-Augmented Generation)检…...

RabbitMQ ③-Spring使用RabbitMQ
Spring使用RabbitMQ 创建 Spring 项目后,引入依赖: <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-amqp --> <dependency><groupId>org.springframework.boot</groupId><artifac…...
测试文章标题01
模型上下文协议(Model Context Protocol, MCP)深度解析 一、MCP的核心概念 模型上下文协议(Model Context Protocol, MCP)是一种用于规范机器学习模型与外部环境交互的标准化框架。其核心目标是通过定义统一的接口和数据格式&am…...

linux中常用的命令(四)
目录 1-cat查看文件内容 2-more命令 3-less命令 4-head命令 5-tail命令 1-cat查看文件内容 cat中的一些操作 -b : 列出行号(不含空白行)-E : 将结尾的断行以 $ 的形式展示出来-n : 列出行号(含空白行)-T : 将 tab 键 以 ^I 显示…...
2025年阿里云大数据ACP高级工程师认证模拟试题(附答案解析)
这篇文章的内容是阿里云大数据ACP高级工程师认证考试的模拟试题。 所有模拟试题由AI自动生成,主要为了练习和巩固知识,并非所谓的 “题库”,考试中如果出现同样试题那真是纯属巧合。 1、下列关于MaxCompute的描述中,错误的是&am…...
【FAQ】HarmonyOS SDK 闭源开放能力 — PDF Kit
1.问题描述: 预览PDF文件,文档上所描述的loadDocument接口,可以返回文件的状态,并无法实现PDF的预览,是否有能预览PDF相关接口? 解决方案: 1、执行loadDocument进行加载PDF文件后,…...
二元随机响应(Binary Randomized Response, RR)的翻转概率
随机响应(Randomized Response)机制 ✅ 回答核心: p 1 1 e ε 才是「翻转概率」 \boxed{p \frac{1}{1 e^{\varepsilon}}} \quad \text{才是「翻转概率」} p1eε1才是「翻转概率」 而: q e ε 1 e ε 是「保留真实值」…...
hive两个表不同数据类型字段关联引发的数据倾斜
不同数据类型引发的Hive数据倾斜解决方案 #### 一、原因分析 当两个表的关联字段存在数据类型不一致时(如int vs string、bigint vs decimal),Hive会触发隐式类型转换引发以下问题: Key值的精度损失:若关联字…...

利用SSRF击穿内网!kali靶机实验
目录 1. 靶场拓扑图 2. 判断SSRF的存在 3. SSRF获取本地信息 3.1. SSRF常用协议 3.2. 使用file协议 4. 172.150.23.1/24探测端口 5. 172.150.23.22 - 代码注入 6. 172.150.23.23 SQL注入 7. 172.150.23.24 命令执行 7.1. 实验步骤 8. 172.150.23.27:6379 Redis未授权…...

DVWA在线靶场-xss部分
目录 1. xxs(dom) 1.1 low 1.2 medium 1.3 high 1.4 impossible 2. xss(reflected) 反射型 2.1 low 2.2 medium 2.3 high 2.4 impossible 3. xss(stored)存储型 --留言板 3.1 low 3.2 medium 3.3 high 3.…...

Go 语言 slice(切片) 的使用
序言 在许多开发语言中,动态数组是必不可少的一个组成部分。在实际的开发中很少会使用到数组,因为对于数组的大小大多数情况下我们是不能事先就确定好的,所以他不够灵活。动态数组通过提供自动扩容的机制,极大地提升了开发效率。这…...
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
在之前的文章ExoPlayer中常见MediaSource子类的区别和使用场景中介绍了Exoplayer中各种子MediaSource的使用场景,这篇我们着重详细介绍下实现多路流混合播放的用法。常见的使用场景有:视频文件电影字幕、正片视频广告视频、背景视频背景音乐等。 初始化…...
深入浅出:Java 中的动态类加载与编译技术
1. 引言 Java 的动态性是其强大功能之一,允许开发者在运行时加载和编译类,从而构建灵活、可扩展的应用程序。动态类加载和编译在许多高级场景中至关重要,例如插件系统、动态代理、框架开发(如 Spring)和代码生成工具。Java 提供了两大核心机制来实现这一目标: 自定义 Cl…...