Muduo网络库源码分析之对socket及其相关操作的封装

Muduo网络库源码分析之Acceptor和TcpServer Acceptor 用于 accept 一个 TCP 连接,accept 接受成功后通知 TCP 连接的使用者。Acceptor 主要是供 TcpServer 使用的,其生命期由后者控制。一个 Acceptor 相当于持有服务端的一个 socket 描述符,该 socket 可以 accept 多个 TCP 客户连接,这个 accept 操作就是 Acceptor 实现的。 这里用到了一些封装好 阅读详情

主要涉及到的类和实现文件有:

  1. Endian.h
    提供了字节序转换的函数。
  2. Socket.h/Socket.cc
    socketfd 的封装,提供了绑定地址、开始listen、接受连接等操作,并可设置套接字选项。
  3. InetAddress.h/InetAddress.cc
    套接字地址的封装,提供了多种方式初始化一个地址,还提供方法从地址中拿到 ip 和 port。
  4. SocketsOps.h/SocketsOps.cc
    封装了 socket 相关的一些操作,提供给 Socket 和 InetAddress 用。

这部分就是基本的 TCP 套接字编程和套接字选项的知识,代码逻辑也很简单,推荐看下 UNP卷一 的相关章节。

下面逐一看下这几个相关的文件。

字节序转换部分(Endian.h)

#ifndef MUDUO_NET_ENDIAN_H
#define MUDUO_NET_ENDIAN_H

#include <stdint.h>
#include <endian.h>

namespace muduo
{
   
   
namespace net
{
   
   
namespace sockets
{
   
   

// the inline assembler code makes type blur,
// so we disable warnings for a while.
#if defined(__clang__) || __GNUC_PREREQ (4,6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wold-style-cast"

/* uint64_t 的整形数字由机器字节序转化为网络字节序 */
inline uint64_t hostToNetwork64(uint64_t host64)
{
  return htobe64(host64);
}

/* uint32_t 的整形数字由机器字节序转化为网络字节序 */
inline uint32_t hostToNetwork32(uint32_t host32)
{
  return htobe32(host32);
}

/* uint16_t 的整形数字由机器字节序转化为网络字节序 */
inline uint16_t hostToNetwork16(uint16_t host16)
{
  return htobe16(host16);
}

/* uint64_t 的整形数字由网络字节序转化为机器字节序 */
inline uint64_t networkToHost64(uint64_t net64)
{
  return be64toh(net64);
}

/* uint32_t 的整形数字由网络字节序转化为机器字节序 */
inline uint32_t networkToHost32(uint32_t net32)
{
  return be32toh(net32);
}

/* uint16_t 的整形数字由网络字节序转化为机器字节序 */
inline uint16_t networkToHost16(uint16_t net16)
{
  return be16toh(net16);
}
#if defined(__clang__) || __GNUC_PREREQ (4,6)
#pragma GCC diagnostic pop
#else
#pragma GCC diagnostic warning "-Wconversion"
#pragma GCC diagnostic warning "-Wold-style-cast"
#endif
}
}
}

#endif  // MUDUO_NET_ENDIAN_H

Socket

Socket.h

#ifndef MUDUO_NET_SOCKET_H
#define MUDUO_NET_SOCKET_H

#include <boost/noncopyable.hpp>

// struct tcp_info is in <netinet/tcp.h>
struct tcp_info;

namespace muduo
{
///
/// TCP networking.
///
namespace net
{

class InetAddress;

/// It closes the sockfd when desctructs.
/* sock 描述符 fd的封装,实现了 绑定了地址,开始监听 并接受连接 */
class Socket : boost::noncopyable
{
 public:
  explicit Socket(int sockfd)
    : sockfd_(sockfd)
  { }

  /* close(sockfd_) */
  ~Socket();

  /* 返回 这个 socket 的 fd*/
  int fd() const { return sockfd_; }

  /* 获取与这个套接字相关联的选项,成功返回 true */
  bool getTcpInfo(struct tcp_info*) const;
  bool getTcpInfoString(char* buf, int len) const;

  /* 调用bind,绑定sockaddr */
  void bindAddress(const InetAddress& localaddr);
  /* 调用listen ,开始监听*/
  void listen();

  /// On success, returns a non-negative integer that is
  /// a descriptor for the accepted socket, which has been
  /// set to non-blocking and close-on-exec. *peeraddr is assigned.
  /// On error, -1 is returned, and *peeraddr is untouched.
  /* 调用accept,成功返回non-blocking和close-on-exec属性的 connfd */
  int accept(InetAddress* peeraddr);

  /* 关闭"写"方向的连接 */
  void shutdownWrite();


  /* 是否使用 Nagle 算法 */
  void setTcpNoDelay(bool on);

  /* 是否重用本地地址 */
  void setReuseAddr(bool on);

  /* 是否重用本地端口 */
  void setReusePort(bool on);

  /* 是否定期检测连接数否存在 */
  void setKeepAlive(bool on);

 private:
  const int sockfd_; // sockket fd
};

}
}
#endif  // MUDUO_NET_SOCKET_H

Socket.cc

#include <muduo/net/Socket.h>

#include <muduo/base/Logging.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/SocketsOps.h>

#include <netinet/in.h>
#include <netinet/tcp.h>
#include <strings.h>  // bzero
#include <stdio.h>  // snprintf

using namespace muduo;
using namespace muduo::net;

/* 析构时关闭 fd */
Socket::~Socket()
{
  sockets::close(sockfd_);
}


bool Socket::getTcpInfo(struct tcp_info* tcpi) const
{
  socklen_t len = sizeof(*tcpi);
  bzero(tcpi, len);
  return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0;
}

/* 将TCP信息转化为字符串 */
bool Socket::getTcpInfoString(char* buf, int len) const
{
  struct tcp_info tcpi;
  bool ok = getTcpInfo(&tcpi);
  if (ok)
  {
    snprintf(buf, len, "unrecovered=%u "
             "rto=%u ato=%u snd_mss=%u rcv_mss=%u "
             "lost=%u retrans=%u rtt=%u rttvar=%u "
             "sshthresh=%u cwnd=%u total_retrans=%u",
             tcpi.tcpi_retransmits,  // Number of unrecovered [RTO] timeouts
             tcpi.tcpi_rto,          // Retransmit timeout in usec
             tcpi.tcpi_ato,          // Predicted tick of soft clock in usec
             tcpi.tcpi_snd_mss,
    
Linux C/C++进阶:从系统原理到AI Infra、音视频等核心领域实战 在计算机系统开发领域,深入理解操作系统、网络和编译器原理是构建高性能、高可靠性软件的基础。这些底层知识构成了从基础服务到前沿应用的技术支柱,其核心价值在于实现对计算资源的精细控制和极致性能优化。掌握Linux系统编程、现代C++特性及并发模型,使开发者能够应对高并发、低延迟的复杂工程挑战。这种能力在AI基础设施(AI Infra)、音视频处理、嵌入式系统等垂直场景中尤为重要,例如在大模型推理优化、实时流媒体传输等具体实践中,扎实的系统级编程功底是技术突破的关键。本文聚焦于为有一定基础的C/C++开发者规划一 阅读详情

相关推荐

C++开源项目学习指南:从入门到精通的实战路径

C++作为一门支撑操作系统、游戏引擎、数据库等核心系统的基础编程语言,其高性能和底层控制能力是构建复杂软件系统的基石。理解其核心原理,如内存管理、编译过程和并发模型,对于掌握系统级编程至关重要。现代C++标准(C++11/14/17/20)引入了智能指针、移动语义等特性,极大地提升了开发效率和代码安全性,其技术价值在于能够构建出既高效又可靠的大型软件。在实际应用场景中,无论是开发**高性能网络服务器**、**实时图形渲染引擎**,还是构建分布式存储系统,深入学习和借鉴优秀的开源项目都是快速提升工程能力的捷径

weixin_30647065的博客 408

GCC 中文手册 - 摘自纯C论坛

GCCSection: GNU Tools (1)Updated: 2003/12/05Index Return to Main Contents   NAMEgcc,g++-GNU工程的C和C++编译器(egcs-1.1.2)   总览(SYNOPSIS)gcc[option|filename ]... g++[option|filename ]... 警告(WARNIN

跪羊图 4706

muduo库的TcpServer和TcpConnection用法

TcpServer是muduo库很重要的一个类,它结合TcpConnection、Acceptor构成了一套完整的对I/O触发事件的处理机制。那么它们具体是怎么工作的呢? 先来看一个例子:

FreeeLinux's blog 3518

汇编语言与接口技术(第4版)清华大学出版社 第2章 80*86微处理器 课后题答案

汇编语言与接口技术(第4版)清华大学出版社 第2章 80*86微处理器 课后题答案

m0_51658788的博客 3605

Sourcetree与Gitee的完美协作:从身份验证到推送成功的全流程指南

本文提供了一份详细的Sourcetree与Gitee协作全流程指南,重点解决身份验证失败、Git版本配置及远端仓库设置等常见问题。通过分步讲解,帮助用户掌握从克隆、提交到成功推送的完整操作,并整合了使用个人访问令牌进行身份验证等关键热词信息,确保Windows与MacOS用户都能顺畅完成代码管理。

m2n3b4v5c6的博客 708

投入产出表之直接消耗系数和完全消耗系数计算--基于Excel

介绍 上篇博客已介绍投入产出表的结构类型及意义解读,在此就不重复写了。 投入产出法中相对稳定的因素是一些系数,根据投入产出表可以计算很多系数: 案例 案例数据即流量矩阵,采用的是中国2012年的部分行业数据,若有不对,请批评指正哈。 直接消耗系数的计算 根据上表和直接消耗系数的计算公式,直接消耗系数矩阵通常用A表示。农林牧渔产品和服务部门对其他部门产品的直接消耗系数分别为: 这些消耗系数的经济意义是,农、林、牧、渔产品和服务部门每生产单位(1亿元)总产出,要直接消耗0.1378亿元本部门产品,0.26

m0_46271335的博客 7万+

从数据库到数据仓库:数据仓库导论

本文为数据仓库导论,旨在介绍数据仓库的基本理念和应用场景,帮助读者理解数据仓库的重要性及其在企业中的实际应用。

探索大数据世界 - 深入解析数据存储、分布式计算与人工智能 2784

什么是 SAP Fiori 的 Technical Catalog

笔者之前的文章曾经提到一个叫做本文介绍 Technical Catalog 这个概念在 SAP Fiori 技术体系中的作用。首先我们如何在系统里查看这个 Catalog SAP_BASIS_TCR_T 里面包含的内容呢?如果大家照着本文开头那篇文章里提到的步骤,那么在自己系统里会创建好名叫的 PFCG role.我们登录 ABAP 系统,启动事务码 PFCG,打开这个 role, 就能看到它。展开之后,发现它扮演着一个容器的角色,里面包含了很多 ABAP 对象。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 742

Claude Code 100个真实案例 - 用AI搭建LangChain多工具Agent(自主搜索+查询)

本案例展示如何使用 Claude Code 搭建一个 LangChain 多工具 Agent 系统。Agent 能够自主决定调用搜索引擎、数据库查询、天气查询、计算器等工具,像人类助手一样拆解问题并逐步解决。

yueyeguzhuo的专栏 557

模拟电路综合笔试题解析

本专栏预计更新60期,当前为第10期,文章约6000字,旨在帮助读者掌握模拟电路笔试的核心知识点与实战技巧。文章分为五个章节,涵盖基础理论、高频考点、大厂题目解析等内容。首先,文章详细解析了DC-DC与LDO的区别及选型依据,并通过真题分析帮助读者理解其应用场景。接着,文章深入探讨了运放电路设计、同步降压电路设计等高频考点,并结合实际案例提供解决方案。此外,文章还分享了特斯拉、华为、大疆等大厂的面试题及解析,帮助读者应对复杂电路设计挑战。最后,文章总结了模拟电路设计中的关键技巧与优化方法,为读者提供全面的笔

启芯硬件的博客 468

ArcGIS Pro 3.4 二次开发 - 地理数据库

本文介绍了在ArcGIS Pro SDK 3.4和.NET 8环境下,如何操作地理数据库的多种方法。首先,通过路径打开文件地理数据库,并处理可能出现的异常。其次,使用连接属性或sde文件路径打开企业级地理数据库。此外,还展示了如何从项目项、要素图层中获取地理数据库,以及如何执行SQL语句。最后,文章详细说明了如何从地理数据库中获取单个定义或定义列表,包括表定义、要素类定义、关系类定义和要素数据集定义。这些操作均在后台线程中执行,确保应用程序的响应性。

Winemonk 943

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: eventfd 的分析与具体例子
下一篇: C++智能指针的分析与使用
Tanswer_
博客等级 码龄11年 231粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值