news 2026/10/19 4:56:51

仿muduo实现高并发服务器——端对端Socket.hpp

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
仿muduo实现高并发服务器——端对端Socket.hpp


目录

    • 摘要
    • 注释
      • 3.1 回顾
      • 3.2 新知识
      • 3.3 注意
      • 3.4 反思
    • 正文
      • 4.1 生命周期与返回值约定
      • 4.2 服务端路径
      • 4.3 收发与阻塞
      • 4.4 开发中遇到的问题
    • 总结
    • 常见问题
    • 标签

摘要

Socket.hpp 是 header-only 的单句柄 TCP 封装,唯一成员为int _sockfd,默认构造置 -1,析构close后复位。对外提供Create / Bind / Listen / Accept / Connect / Recv / Send / Close,另有SetNonBlock、SetNonBlockRecv / SetNonBlockSend与CreateServer / CreateClient两个组合入口。价值在于把系统调用返回值判定、sockaddr_in填充与字节序转换收在一处。注释段自述:本实现保证 HTTP 请求的服务端而非客户端。

代码仓库:https://gitee.com/btshadow/Ubuntu_learning/blob/master/October/10-17/muduo/src/server.hpp

注释

3.1 回顾

htons/ntohs:TCP/IP 规定用大端序,即网络字节序;本机算出要发到网络用htons/htonl,从网络收到转本机用ntohs/ntohl。Bind与Connect里的htons(port)属于服务端自身绑定、要让客户端看到该端口的那一侧。
accept 二、三参数:第二参数是输出参数,存放对端地址;第三参数是值-结果参数,传入时为 addr 缓冲区大小,返回时为实际写入长度(见 bug3)。
ET 模式:epoll 的边缘触发,只有状态变化(从无到有/从有到多)时通知一次,对比 LT。本文件未含 epoll,仅记录。

3.2 新知识

noexcept(true)等价于noexcept,是"不抛异常"的显式声明;内部真抛了异常则直接std::terminate()。承诺的是不抛 C++ 异常,不是调用一定成功。价值在于移动构造/移动赋值标 noexcept 后,std::vector等容器扩容走移动而非拷贝。只在确实不抛处用(移动构造、swap、析构、getter),可能分配内存或抛业务异常的不标。本文件中带 noexcept 的只有注释抄录的listen原型。

3.3 注意

sockaddr_in在 bind 与 connect 前有必要清空(Bind、Connect各有memset),accept 时没必要,因为 accept 内是覆盖式写入(Accept未 memset)。
EAGAIN与EINTR作为读/写异常:EAGAIN 关联非阻塞(MSG_DONTWAIT),EINTR 关联信号,与非阻塞关系小(Recv、Send的 errno 判定)。
客户端无需 bind:客户端间各自独立且难以手动管理,内核已代做,故CreateClient只有 Create + Connect。

3.4 反思

测试时太大意了,主要是不想测试、想快点结束,结果代码本身没有 bug,却因测试方式以为有 bug。

正文

4.1 生命周期与返回值约定

Socket()置_sockfd = -1,Socket(int)接管外部 fd,Fd()取值;析构close后置 -1。Close()只close不复位_sockfd,故析构时会对同一 fd 再close一次。每个系统调用失败路径都走ERR_LOG,成功的组合入口用INF_LOG。

4.2 服务端路径

CreateServer(port, ip = "0.0.0.0")依次Create→Bind→Listen,成功后INF_LOG并调SetReuseAddrPort。Create用socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);Bind先memset再填sin_family、htons(port),地址由inet_pton写入sin_addr,旧的inet_addr写法留在注释中;Listen缺省MAX_LISTEN = 1024。SetReuseAddrPort对SO_REUSEADDR与SO_REUSEPORT各setsockopt一次,位置在 bind/listen 之后,失败只记录。

4.3 收发与阻塞

Recv/Send直接转发系统调用,n <= 0时若 errno 为EAGAIN或EINTR返回 0,否则ERR_LOG后返回 -1;Send另有n == 0的独立日志分支。SetNonBlockRecv/SetNonBlockSend以MSG_DONTWAIT调用。SetNonBlock用F_GETFL取标志,再F_SETFL | O_NONBLOCK。客户端方向CreateClient只有 Create 与 Connect,不含 Bind,Connect同样 memset、htons、inet_pton。

4.4 开发中遇到的问题

bug1:INADDR_ANY是 0 不是字符串,极易误会(注释记 [30min])。原写法const std::string& ip = INADDR_ANY已注释掉,现默认值为"0.0.0.0",仍交给inet_pton转换。
bug2:测试时注意,监听套接字不能用于通信。标注位于Send()内。
bug3:accept 的第三参数同时作为输入输出参数,调用前须给出缓冲区大小:

// Accept()// 原:socklen_t len;socklen_t len=sizeof(client_addr);

总结

封装边界是套接字生命周期加系统调用的返回判定;三条注意分别落在Bind/Connect的 memset、Recv/Send的 errno 分支、CreateClient不 Bind,bug3 正是"值-结果参数"未传初值。bug1 属类型不匹配,bug2 属套接字角色混用。

常见问题

  1. 为何Bind、Connect要 memset 而Accept不用?前两者是值传入,Accept内覆盖式写入,client_addr无需清空。
  2. 为何INADDR_ANY不能当std::string默认参数?它是 0 而非字符串(bug1),现用"0.0.0.0"经inet_pton转换。
  3. Recv/Send中EAGAIN与EINTR为何都返回 0?二者都不视为致命错误,交由上层下轮再试。
  4. bug3 中 len 不初始化会怎样?accept把它当输入缓冲区大小,未给值即未定义,故须socklen_t len = sizeof(client_addr)。

标签

C++、TCP Socket 封装、inet_pton、EAGAIN/EINTR、header-only

【统计:全文约 1180 字 / 原代码 256 行 / 比例约 4.6;注释字段小节 4 个 / 成文 bug 3 处】

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 4:56:21

TCP三次握手四次挥手详解:从原理到抓包实战

1. 为什么“三次握手&#xff0c;四次挥手”总被讲得云里雾里1.1 从一次真实的排查经历说起几年前我帮一个朋友排查他公司内网的一个怪问题&#xff1a;两台服务器之间偶尔会出现连接建立成功但数据发不出去的情况&#xff0c;重启就好了&#xff0c;过一阵又复现。他翻了一堆文…

作者头像 李华
网站建设 2026/10/19 4:53:46

PS设计素材包:100+字体+2000+图标+500+图表+1000+商务图片

资源概述 这是一份全面的PS设计素材包&#xff0c;包含字体、图标、图表和商务人物图片四大类别。整个素材包共计153个文件&#xff0c;总大小约6.8GB&#xff0c;涵盖了从文字排版到视觉配图的设计需求。 文中资料 查阅配套内容 素材内容详解 字体包&#xff08;100&#xf…

作者头像 李华
网站建设 2026/10/19 4:53:20

openMVG三维重建第一步:ImageListing入口程序详解与焦距估算

作为一个常年跟三维重建打交道的开发者&#xff0c;我跑过不少SfM流程&#xff0c;从早期的经典工具到现在的轻量级方案都用过。openMVG就是我非常喜欢的一套开源多视图几何库&#xff0c;它把运动恢复结构&#xff08;Structure from Motion&#xff09;的标准流程拆得非常清晰…

作者头像 李华
网站建设 2026/10/19 4:52:50

开源代码评审工作流:用CLI+LLM Agent实现本地化智能Code Review

1. 项目概述&#xff1a;这不是一个工具&#xff0c;而是一套可落地的开源代码评审工作流“open-code-review”这个名字乍一听像某个新发布的 CLI 工具&#xff0c;或者某家大厂刚开源的 AI 代码审查平台。但实际翻遍 GitHub、PyPI、NPM 和主流技术社区&#xff0c;你会发现——…

作者头像 李华
网站建设 2026/10/19 4:52:37

open-code-review:基于CLI与git diff的轻量级AI代码审查范式

1. “open-code-review”不是工具名&#xff0c;而是正在发生的开发范式迁移“open-code-review”这个词最近在 GitHub Trending、Hacker News 和内部技术分享会上高频出现&#xff0c;但它既不是某个新开源项目的仓库名&#xff0c;也不是某家公司的商业化产品代号。我第一次在…

作者头像 李华
网站建设 2026/10/19 4:52:20

后端必学:计算机网络分层模型与TCP/IP排错实战

我以前自认“会写接口、会用数据库”&#xff0c;直到第一次在生产环境排查“接口偶尔超时”这个问题时&#xff0c;整个人是懵的。业务代码翻了三遍没发现异常&#xff0c;数据库也没有慢查询&#xff0c;最后是某位资深同事在终端敲了几条命令&#xff0c;抓了几分钟的包&…

作者头像 李华