当前位置: 首页 > news >正文

网络muduo库的实现(2)

3. 类型设计

1. InetAddress 类型

InetAddress 类作为 sockaddr_in 结构体的包装器,提供对网络地址信息的封装和操作。

class InetAddress
{
private:struct sockaddr_in addr_;  // 底层地址结构体
public:explicit InetAddress(uint16_t port = 0);  // 仅指定端口构造InetAddress(const std::string &ip, uint16_t port);  // 指定IP和端口构造InetAddress(const struct sockaddr_in &addr);  // 通过sockaddr_in构造std::string getIp() const;  // 获取IP地址字符串std::string getIpPort() const;  // 获取IP:端口字符串uint16_t getPort() const;  // 获取端口号const struct sockaddr_in & getSockInet() const;  // 获取底层sockaddr_invoid setSockAddrInet(const struct sockaddr_in &addr);  // 设置底层sockaddr_in// 将主机名解析为IP地址,不更改端口或sin_family// 成功后返回真值,线程安全static bool resolve(const string &hostname, InetAddress &result); 
};

2. Socket 类型

Socket 类封装了 socket 文件描述符的操作,采用 RAII 方式管理资源。

// in <netinet/tcp.h>
struct tcp_info;class InetAddress;class Socket
{
private:const int sockfd_;  // socket文件描述符
public:explicit Socket(int sockfd);  // 通过已有fd构造~Socket();  // 析构时关闭socketint fd() const;  // 获取文件描述符bool getTcpInfo(const struct tcp_info &tcpinfo) const;  // 获取TCP信息bool getTcpInfoString(std::string &buf) const;  // 获取TCP信息字符串void bindAddress(const InetAddress &localaddr);  // 绑定地址void listen();  // 开始监听int accept(InetAddress &peeraddr);  // 接受连接void shutdownWrite();  // 关闭写方向// 设置socket属性void setTcpNoDelay(bool on);  // 设置TCP_NODELAYvoid setReuseAddr(bool on);  // 设置SO_REUSEADDRvoid setReusePort(bool on);  // 设置SO_REUSEPORTvoid setKeepAlive(bool on);  // 设置SO_KEEPALIVE
};

3. Acceptor 类型

Acceptor 类负责服务器端监听新连接,封装了监听 socket 和连接接受逻辑。

class EventLoop;
class InetAddress;class Acceptor
{
public:// 新连接回调函数类型:参数为新连接的sockfd和对端地址using NewConnectionCallback = std::function<void(const int sockfd, const InetAddress &)>;
private:Socket acceptSocket_;  // 监听socketNewConnectionCallback newConnectionCallback_;  // 新连接建立后的回调bool listenning_;  // 是否正在监听int idleFd_;  // 空闲文件描述符,用于处理文件描述符耗尽情况void handleRead();  // 处理读事件(新连接到来)
public:Acceptor(const InetAddress &listenAddr, bool resueport);  // 构造函数~Acceptor();  // 析构函数void setNewConnectionCallback(const NewConnectionCallback& cb);  // 设置新连接回调bool listenning() const;  // 判断是否正在监听void listen();  // 开始监听
};

4. TcpConnection 全相关连接类型

TcpConnection 类封装一次 TCP 连接的生命周期管理,是网络库的核心类。

class Channel;
class EventLoop;
class Socket;class TcpConnection : public std::enable_shared_from_this<TcpConnection>
{
private:// 连接状态枚举enum class StateE { kDisconnected, kConnecting, kConnected, kDisconnecting };const std::string name_;  // 连接名称StateE state_;  // 当前连接状态std::unique_ptr<Socket> socket_;  // 连接socketconst InetAddress localAddr_;  // 本地地址const InetAddress peerAddr_;  // 对端地址size_t highWaterMark_;  // 高水位标记,用于流量控制std::string inputBuffer_;  // 输入缓冲区std::string outputBuffer_;  // 输出缓冲区// 各类回调函数ConnectionCallback connectionCallback_;  // 连接状态变化回调MessageCallback messageCallback_;  // 消息到达回调WriteCompleteCallback writeCompleteCallback_;  // 写完成回调HighWaterMarkCallback highWaterMarkCallback_;  // 高水位回调CloseCallback closeCallback_;  // 关闭回调private:// 事件处理函数void handleRead(const Timestamp &receiveTime);  // 处理读事件void handleWrite();  // 处理写事件void handleClose();  // 处理关闭事件void handleError();  // 处理错误事件void setState(StateE s);  // 设置连接状态
public:// 构造函数:参数为连接名称、sockfd、本地地址、对端地址TcpConnection(const std::string &name,int sockfd,const InetAddress &localAddr,const InetAddress &peerAddr);~TcpConnection();  // 析构函数EventLoop * getLoop() const;  // 获取所属事件循环const std::string & name() const;  // 获取连接名称const InetAddress & localAddress() const;  // 获取本地地址const InetAddress & peerAddress() const;  // 获取对端地址bool connected() const;  // 判断是否已连接bool getTcpInfo(struct tcp_info &) const;  // 获取TCP信息std::string getTcpInfoString() const;  // 获取TCP信息字符串// 数据发送接口void send(const void *message, int len);void send(const std::string &message);void shutdown();  // 关闭连接void forceClose();  // 强行关闭连接void forceCloseWithDelay(int64_t seconds);  // 延迟强行关闭void setTcpNoDelay(bool on);  // 设置TCP_NODELAY// 设置回调函数void setConnectionCallback(const ConnectionCallback & cb);void setMessageCallback(const MessageCallback &cb);void setWriteCompleteCallback(const WriteCompleteCallback &cb);void setHighWaterMarkCallback(const HighWaterMarkCallback &cb, size_t highWaterMark);void setCloseCallback(const CloseCallback &cb);std::string & inputBuffer();  // 获取输入缓冲区std::string & outputBuffer();  // 获取输出缓冲区void connectEstablished();  // 连接建立完成void connectDestroyed();  // 连接销毁
};

5. TcpServer 服务器类型

TcpServer 类作为服务器端入口,管理 acceptor 和连接池,提供服务器启动和连接管理功能。

class Acceptor;
class EventLoop;
class EventLoopThreadPool;class TcpServer
{
public:using ThreadInitCallback = std::function<void(EventLoop*)>;  // 线程初始化回调// 服务器选项枚举enum class Option{kNoReusePort,  // 不重用端口kReusePort     // 重用端口};
private:using ConnectionMap = std::map<std::string, TcpConnectionPtr>;  // 连接映射表EventLoop *loop_;  // 主事件循环const std::string hostport_;  // 主机端口字符串const std::string name_;  // 服务器名称std::unique_ptr<Acceptor> acceptor_;  //  acceptor对象std::shared_ptr<EventLoopThreadPool> threadPool_;  // 事件循环线程池ConnectionCallback connectionCallback_;  // 连接回调// 新连接处理函数void newConnection(int sockfd, const InetAddress & peerAddr);// 移除连接void removeConnection(const TcpConnectionPtr & conn);void removeConnectionInLoop(const TcpConnectionPtr &conn);
};

4. 类图

5. TcpServer 对象的创建和连接建立过程

    //Buffer * outputBuffer();std::string & outputBuffer();void setCloseCallback(const CloseCallback &cb);void connectEstablished();void connectDestroyed(); 
};

TcpServer 类完整定义

class Acceptor;
class EventLoop;
class EventLoopThreadPool;class TcpServer
{
public:using ThreadInitCallback = std::function<void(EventLoop*)>;  // 线程初始化回调enum class Option{kNoReusePort,  // 不重用端口kReusePort     // 重用端口};
private:using ConnectionMap = std::map<std::string, TcpConnectionPtr>;  // 连接映射表EventLoop * loop_;  // 主事件循环const std::string hostport_;  // 主机端口字符串const std::string name_;  // 服务器名称std::unique_ptr<Acceptor> acceptor_;  // Acceptor对象std::shared_ptr<EventLoopThreadPool> threadPool_;  // 事件循环线程池ConnectionCallback connectionCallback_;  // 连接回调函数// 新连接处理函数void newConnection(int sockfd, const InetAddress & peerAddr);// 移除连接void removeConnection(const TcpConnectionPtr & conn);void removeConnectionInLoop(const TcpConnectionPtr &conn);
};

实施和测试

2. 问题

我们通过类型封装 Sockets API,目的之一是在进行网络编程时,从 Sockets API 的琐碎细节中解脱出来。但尚未解决高并发的问题。

3. 第二个版本的需求

使用 Reactor (反应堆) 模式实现高性能的服务器程序。

网络开发的基本概念

1. 阻塞 I/O 模式和非阻塞 I/O 模式
  • 阻塞 I/O 模式:缺省或默认状态下,套接字处于阻塞 I/O 模式。当调用 Sockets 函数不能立即完成时,系统内核会使执行程序(进程或线程)进入阻塞状态,等待操作完成。
  • 非阻塞 I/O 模式:若将套接字设置为非阻塞 I/O 模式,调用 Sockets 函数不能立即完成时,系统内核不会阻塞当前程序(进程或线程),而是返回一个错误信息。
2. 可能阻塞的 Sockets 函数分类

将可能阻塞的 Sockets 函数调用分为以下四类:

  1. 输入操作readreadvrecvrecvfrom 和 recvmsg 函数。

    • 阻塞模式:在阻塞 TCP 套接字上调用这些函数时,若接收缓冲区中无数据,进程会阻塞至数据到来(TCP 是字节流,数据到来时进程被唤醒,可能是一个字节或完整分节)。可通过自定义 readn 函数或指定 MSG_WAIT_ALL 标志等待固定数据量。
    • 非阻塞模式:若输入操作无法满足(TCP 至少需 1 字节数据,UDP 需完整数据报),会立即返回 EWOULDBLOCK 错误码(或 EAGAIN,表示资源暂时不可用)。
  2. 输出操作writewritevsendsendto 和 sendmsg 函数。

    • 阻塞模式:对 TCP socket,内核从应用缓冲区向套接字发送缓冲区拷贝数据。若发送缓冲区无可用空间,进程会阻塞至内核腾出空间。
    • 非阻塞模式:若发送缓冲区无空间,输出操作立即返回 EWOULDBLOCK 错误;若有部分空间,返回值为内核可拷贝的字节数(称为 “不足计数”)。UDP 无发送缓冲区,内核直接拷贝数据并传递至下层协议,因此阻塞 UDP 套接字的输出操作不会阻塞。
  3. 接收外来连接accept 函数。

    • 阻塞模式:调用 accept 时若无新连接,进程会阻塞。
    • 非阻塞模式:调用 accept 时若无新连接,返回 EWOULDBLOCK 错误。
  4. 初始化外出连接:TCP 的 connect 函数。

    • TCP 连接建立需三次握手,connect 函数在客户接收 SYN 的 ACK 前不会返回,通常阻塞至少一个 RTT(往返时间),默认超时 75s。
    • 非阻塞模式:若连接不能立即建立,连接建立过程启动(如发送三次握手第一个分组),但返回 EINPROGRESS 错误。需注意同一主机上的连接可能立即建立,因此需处理 connect 返回成功的情况。

说明:系统 V 对不能立即完成的非阻塞 I/O 操作返回 EAGAIN 错误,Berkeley 实现返回 EWOULDBLOCK 错误。多数系统(如 SVR4 和 4.4BSD)将两者定义为相同值(可查看 <sys/errno.h>),本文使用 Posix.1g 规定的 EWOULDBLOCK

http://www.dtcms.com/a/316246.html

相关文章:

  • 计算机算术5-整形除法
  • MySql数据库归档工具pt-archiver
  • Android audio之 AudioDeviceInventory
  • 第三方验收测试报告:软件项目验收中的核心要素
  • 前端权限设计
  • Pandas query() 方法详解
  • 涨薪技术|Kubernetes(k8s)之Pod生命周期(上)
  • Deveco Studio 3.1.0.501 Windows版下载安装教程 - 华为开发者工具安装步骤详解
  • BenchmarkDotNet 性能基准测试
  • 统计鱼儿分布情况 Java
  • 三种灰狼算法求解无人机三维路径规划【MATLAB实现】
  • 2025国赛数学建模C题详细思路模型代码获取,备战国赛算法解析——层次分析法
  • MATLAB实现菲涅尔法全息成像仿真
  • Groovy学习篇章一之—— GDK 探秘:Groovy如何给Java对象“开外挂”,让String也能“跑命令”!
  • 磁悬浮转子的“静音术”:深度解析无接触抑制旋转幽灵的奥秘
  • 基于MCP的智能客服系统:知识库与工单系统深度集成
  • 英语中日期与时间缩写
  • 针对软件定义车载网络的动态服务导向机制
  • CoRL-2025 | 北大“如影随形”具身导航智能体!TrackVLA:复杂自然环境中的具身视觉跟踪
  • cJSON库应用
  • Vulnhuntr:用于识别远程可利用漏洞的开源工具
  • 文字识别在媒资系统的技术原理及应用剖析
  • 数据安全治理——解读数据安全治理与评估服务业务介绍【附全文阅读】
  • Book Shop(Dynamic Programming)
  • Direct12第六章
  • 【LeetCode 热题 100】347. 前 K 个高频元素——(解法一)排序截取
  • 防火墙的区域划分和流量控制
  • Qwen3技术之模型预训练
  • Redis Stream:高性能消息队列核心原理揭秘
  • 数据结构04 栈和队列