C++ 仿muduo高并发服务器:Socket模块
C 仿muduo高并发服务器Socket模块1. 为什么需要封装 SocketLinux 原生 socket API 是一组 C 函数直接使用存在以下问题参数复杂容易出错如sockaddr类型转换、字节序转换。资源管理麻烦fd 需要手动close。错误处理重复每个调用都要判断返回值、打印日志。阻塞/非阻塞、地址重用等选项设置分散。封装成Socket类后提供面向对象的接口语义清晰。利用 RAII 自动关闭 fd需完善析构函数。统一错误日志输出。方便在 Reactor 模型中作为基础组件使用。2. 类定义概览#defineMAX_LISTEN1024classSocket{private:int_sockfd;public:Socket(){}Socket(intfd):_sockfd(fd){}~Socket(){}intFd(){return_sockfd;}boolCreate();boolBind(conststd::stringip,uint16_tport);boolListen(intbacklogMAX_LISTEN);boolConnect(conststd::stringip,uint16_tport);intAccept();ssize_tRecv(void*buf,size_t len,intflag0);ssize_tNonBlockRecv(void*buf,size_t len);ssize_tSend(constvoid*buf,size_t len,intflag0);ssize_tNonBlockSend(void*buf,size_t len);voidClose();boolCreaterServer(uint16_tport,conststd::stringip0.0.0.0,boolblock_flagfalse);boolCreateClient(uint16_tport,conststd::stringip);voidReuseAddress();voidNonBlock();};3. 成员变量与构造/析构int_sockfd;_sockfd套接字文件描述符-1表示无效。Socket():_sockfd(-1){}Socket(intfd):_sockfd(fd){}~Socket(){}析构函数应调用Close()自动关闭 fd当前为空存在资源泄漏风险。改进建议后期我们再加上~Socket(){Close();}4. 核心函数详解4.1Create()创建套接字boolCreate(){_sockfdsocket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(_sockfd0){ERR_LOG(CREATE SOCKET FAILED!!);returnfalse;}returntrue;}AF_INETIPv4 协议族。SOCK_STREAMTCP 流式套接字。IPPROTO_TCPTCP 协议。成功返回非负 fd失败返回-1。4.2Bind()绑定地址boolBind(conststd::stringip,uint16_tport){structsockaddr_inaddr;addr.sin_familyAF_INET;addr.sin_porthtons(port);// 端口转网络字节序addr.sin_addr.s_addrinet_addr(ip.c_str());// IP 转网络字节序socklen_t lensizeof(structsockaddr_in);intretbind(_sockfd,(structsockaddr*)addr,len);if(ret0){ERR_LOG(BIND ADDRESS FAILED!);returnfalse;}returntrue;}htons主机字节序 → 网络字节序16 位。inet_addr点分十进制 IP → 网络字节序 32 位整数。服务器必须bind客户端通常不需要。4.3Listen()开始监听boolListen(intbacklogMAX_LISTEN){intretlisten(_sockfd,backlog);if(ret0){ERR_LOG(SOCKET LISTEN FAILED!);returnfalse;}returntrue;}backlog已完成连接队列的最大长度默认MAX_LISTEN1024。将主动套接字变为被动监听套接字内核开始接受连接。4.4Connect()客户端发起连接boolConnect(conststd::stringip,uint16_tport){structsockaddr_inaddr;addr.sin_familyAF_INET;addr.sin_porthtons(port);addr.sin_addr.s_addrinet_addr(ip.c_str());socklen_t lensizeof(structsockaddr_in);intretconnect(_sockfd,(structsockaddr*)addr,len);if(ret0){ERR_LOG(CONNECT SERVER FAILED!);returnfalse;}returntrue;}向服务器发起 TCP 连接触发三次握手。阻塞模式下会等待连接完成。4.5Accept()接受新连接intAccept(){intnewfdaccept(_sockfd,NULL,NULL);if(newfd0){ERR_LOG(SOCKET ACCEPT FAILED!);return-1;}returnnewfd;}从已完成连接队列取出一个连接返回新的通信 fd。监听 fd 继续监听新 fd 用于和客户端通信。非阻塞模式下无连接时返回-1errno为EAGAIN。4.6Recv()与NonBlockRecv()ssize_tRecv(void*buf,size_t len,intflag0){ssize_t retrecv(_sockfd,buf,len,flag);if(ret0){if(errnoEAGAIN||errnoEINTR){return0;// 暂时无数据}ERR_LOG(SCOKET RECV FAILED!);// 拼写错误SCOKET - SOCKETreturn-1;}returnret;}ssize_tNonBlockRecv(void*buf,size_t len){returnRecv(buf,len,MSG_DONTWAIT);}recv返回实际接收字节数。ret 0对端关闭连接。ret 0EAGAIN/EWOULDBLOCK非阻塞下无数据。EINTR被信号中断。其他真正错误。MSG_DONTWAIT本次接收非阻塞不改变套接字整体属性。4.7Send()与NonBlockSend()ssize_tSend(constvoid*buf,size_t len,intflag0){ssize_t retsend(_sockfd,buf,len,flag);if(ret0){ERR_LOG(SOCKET SEND FAILED!);return-1;}returnret;}ssize_tNonBlockSend(void*buf,size_t len){returnSend(buf,len,MSG_DONTWAIT);}返回实际发送字节数。非阻塞下可能只发送部分数据需要应用层缓冲剩余数据。SIGPIPE信号需忽略否则向已关闭连接发送会崩溃。4.8Close()关闭套接字voidClose(){if(_sockfd!-1)close(_sockfd);_sockfd-1;}关闭 fd置为-1防止重复关闭。4.9CreaterServer()一键创建服务端boolCreaterServer(uint16_tport,conststd::stringip0.0.0.0,boolblock_flagfalse){if(Create()false)returnfalse;if(block_flag)NonBlock();// 注意block_flag 为 true 时反而设非阻塞命名相反if(Bind(ip,port)false)returnfalse;if(Listen()false)returnfalse;ReuseAddress();// 建议移到 Bind 之前returntrue;}默认ip 0.0.0.0监听所有网卡。block_flag命名有歧义实际true表示非阻塞。ReuseAddress()应在Bind()前调用。4.10CreateClient()一键创建客户端boolCreateClient(uint16_tport,conststd::stringip){if(Create()false)returnfalse;if(Connect(ip,port)false)returnfalse;returntrue;}4.11ReuseAddress()地址端口重用voidReuseAddress(){intval1;setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,(void*)val,sizeof(int));val1;setsockopt(_sockfd,SOL_SOCKET,SO_REUSEPORT,(void*)val,sizeof(int));}SO_REUSEADDR允许绑定处于TIME_WAIT的端口服务器可立即重启。SO_REUSEPORT允许多个套接字绑定相同 IP:端口实现负载均衡。val 1表示开启选项0表示关闭。SOL_SOCKET通用套接字层选项。4.12NonBlock()设置非阻塞voidNonBlock(){intflagfcntl(_sockfd,F_GETFL,0);fcntl(_sockfd,F_SETFL,flag|O_NONBLOCK);}获取当前文件状态标志加上O_NONBLOCK再设置回去。非阻塞是 Reactor 模型的基础防止accept/recv/send阻塞 EventLoop 线程。5. 关键知识点知识点说明字节序转换htons/htonl主机转网络ntohs/ntohl网络转主机地址转换inet_addr字符串转网络字节序推荐inet_pton错误处理errnoEAGAIN/EWOULDBLOCK表示非阻塞无数据EINTR表示被信号中断阻塞 vs 非阻塞非阻塞配合 epoll避免线程卡死地址重用SO_REUSEADDR解决 TIME_WAITSO_REUSEPORT支持多进程监听RAII析构自动关闭 fd避免资源泄漏SIGPIPE需忽略防止向已关闭连接发送数据导致进程退出6. 使用示例6.1 服务端#includeserver.hppintmain(){Socket lst_sock;lst_sock.CreaterServer(8500);// 默认阻塞while(1){intnewfdlst_sock.Accept();if(newfd0)continue;Socketcli_sock(newfd);charbuf[1024]{0};intretcli_sock.Recv(buf,1023);if(ret0){cli_sock.Close();continue;}cli_sock.Send(buf,ret);cli_sock.Close();}lst_sock.Close();return0;}6.2 客户端#includeserver.hppintmain(){Socket cli_sock;cli_sock.CreateClient(8500,127.0.0.1);std::string strhello;cli_sock.Send(str.c_str(),str.size());charbuf[1024]{0};cli_sock.Recv(buf,1023);DBG_LOG(%s,buf);return0;}7. 总结Socket类是对 Linux 原生 socket API 的轻量级封装核心接口创建Create绑定Bind监听Listen连接Connect接受Accept收发Recv/Send支持非阻塞版本关闭Close辅助ReuseAddress、NonBlock

相关新闻

第9章:提交项目到GitHub

第9章:提交项目到GitHub

第9章:提交项目到GitHub 本章目标 完整走一遍把项目提交到 GitHub 远程仓库的流程,包括 GitHub 特有的 Personal Access Token(PAT) 认证、代理配置、以及命令行 / TortoiseGit 两套操作。与 第8章:提交项目到Gitee 对…

2026/9/24 17:46:43 阅读更多 →
第 3 篇 · p2m 内存类型分类

第 3 篇 · p2m 内存类型分类

p2m 表项不只记"对应哪个 MFN",还带一个类型标签(p2m_type),决定访问它时的行为。这一篇把 Xen 的 p2m 类型讲透:完整枚举 各自用例,以及它们之上两个容易混淆的"分组/空间"概念——类…

2026/9/24 17:46:43 阅读更多 →
计算机毕业设计之基于MySQL的校园二手商城的设计及实现

计算机毕业设计之基于MySQL的校园二手商城的设计及实现

随着新世纪无纸化办公方式的普及,自动化信息处理和基于网络的信息交互方式已被广泛应用。现在很多行业基本上都是交由计算机进行管理和测试,网络与计算机已成为整个线上管理体系中的重要组成部分。虽然信息技术广泛应用和数据存取更加方便,但…

2026/9/24 17:46:43 阅读更多 →

最新新闻

【Coze】【视频】治愈系老爷爷工作流

【Coze】【视频】治愈系老爷爷工作流

今天给大家演示一个 老爷爷语录视频自动生成工作流。该工作流通过大语言模型和图像生成模型的协作,自动完成从文本语录生成、格式化处理、配图生成,再到视频合成和音频配乐的完整流程。结合效果展示,用户只需提供简单的输入,就能得到带有温馨画面和背景音乐的成品视频,大幅…

2026/9/24 18:27:12 阅读更多 →
基于SpringBoot的美食推荐系统实战:协同过滤算法与部署解析

基于SpringBoot的美食推荐系统实战:协同过滤算法与部署解析

每年到这个时间段,我的私信里总是涌入同一类问题:SpringBoot学完了但没项目练手怎么办?课程设计选什么题能不撞车又拿高分?面试时项目经历讲不出亮点怎么办?今天就把我打磨过很多遍的一个实战项目——基于SpringBoot的…

2026/9/24 18:27:12 阅读更多 →
快速排序实战笔记:从分治原理到代码优化与边界排查

快速排序实战笔记:从分治原理到代码优化与边界排查

如果你和我一样,是靠刷 LeetCode 硬啃基础算法过来的,那“快速排序”这四个字你绝对不陌生。很多人在基础算法集训里把它当成一道“背模板题”——敲一遍快排代码、跑通几个用例,就觉得自己会了。但真到了手撕代码、处理大数据量、甚至面试被…

2026/9/24 18:27:12 阅读更多 →
从原理到实战:搭建轻量级沙箱环境与隔离技术解析

从原理到实战:搭建轻量级沙箱环境与隔离技术解析

说到沙箱技术,很多人的第一印象可能是留档取证或者安全分析人员的神秘工具,但把它放到日常软件工程里,它其实就是一个“能让你胆大心细地跑不受信任代码”的基础设施。我最早接触沙箱,是因为要分析一系列可疑的 Office 文档&#…

2026/9/24 18:27:12 阅读更多 →
【Coze】【视频】小人国风格动画工作流

【Coze】【视频】小人国风格动画工作流

今天给大家演示一个 微观小人国场景构建与多模态生成的 Coze 工作流。这个工作流的设计目标,是将用户输入的主题转化为成体系的微观生活场景,再通过大模型生成文本、图像与视频内容,最终形成可用于创作与展示的多模态成果。从场景文本构思,到文生图提示词,再到批量图像生成…

2026/9/24 18:27:12 阅读更多 →
MinioUtil工具类设计实战:Java对象存储封装与踩坑指南

MinioUtil工具类设计实战:Java对象存储封装与踩坑指南

做后端开发这几年,文件存储始终是个绕不开的话题。早期我接触过FastDFS,也折腾过自建FTP,后来云厂商的对象存储也用了一阵子,但版权费用和灵活性总让人不太舒服。直到在一个内部管理系统里遇到Minio,我才发现这个S3兼容…

2026/9/24 18:26:12 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →