TCP网络编程库——Muduo库
目录
1,Muduo库的说明
2,Muduo库的主要组件
3,Muduo常用的类接口
4,Muduo库的代码运用
5、Muduo库的工作流程
6、特点与优势
1,Muduo库的说明
Muduo库是一个基于非阻塞IO和IO多路复用的C++高并发TCP网络编程库,它基于Reactor模式实现,并支持多线程并发处理的网络库,使用的线程模型是one loop per thread。
注意:Reactor模式和one loop per thread模型请在此连接下观看:Reactor模式
2,Muduo库的主要组件
1,TCPServer类:该类用于创建和管理TCP服务器。用户可以通过TcpServer设置连接建立、消息到达等事件的回调处理函数。
2,EventLoop类:事件循环对象,负责监听和处理事件,它是一个真正进行事件监控的类。事件循环是Muduo库的核心组件,每个线程线程都有一个独立的EventLoop对象,即事件循环。事件循环负责监听文件描述符的事件(如可读、可写等),它包含了一个事件队列和事件处理函数。当事件发生时,EventLoop会将事件放入队列中,并依次调用相应的事件回调函数来处理这些事件。TCPServer通过创建多个EventLoop来充分利用多核CPU的并行处理能力。
3,TcpConnection类:它代表了一个TCP连接,封装了与特定客户端的所有交互,包括数据的发送和接收、连接的建立和断开等。在连接建立时,TcpConnection会设置相关的回调函数进行事件的监听。在连接维护阶段,TcpConnection会处理读(接收)事件和写(发送)事件,确保数据的正确传输。在连接关闭时,TcpConnection会触发相关的回调函数处理连接关闭时的清理工作。
4,TcpClient类:一个用于管理TCP客户端连接的重要组件。TcpClient类主要负责发起TCP连接,并在连接建立后管理这个连接。当连接建立成功后,TcpClient会创建一个TcpConnection对象通过回调函数来管理这个连接。
5,Buffer类:它是一个高效的数据缓冲区,用于存储从网络中接收到的数据以及待发送的数据。当创建该类对象时,我们可以通过调用Buffer类的读写接口来向缓冲区中写入数据和从缓冲区中读取数据。在读写过程中,Buffer类会自动处理内存分配、扩容和回收等底层细节。
3,Muduo常用的类接口
1,TCPServer类接口
// 用于设置线程池中线程的数量,即设置reactor线程数量
// 默认情况下只有一个reactor线程,即主线程,它即获取新连接,又处理IO事件
void setThreadNum(int numThreads);
// 启动服务器,开始监听指定的端口,准备接受客户端的连接。
void start();
// 设置连接建立或关闭时的回调函数,该回调函数会在有新的连接建立或现有连接断开时被调用。其中,该回调函数自定义设置,且该回调函数接受一个const TcpConnectionPtr& 参数,代表连接对象。TcpConnectionPtr定义为:typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;下面信息处理的回调函数同理
void setConnectionCallback(const ConnectionCallback& cb);
自定义函数cp如:void cp(const muduo::net::TcpConnectionPtr &conn);
// 设置消息处理的回调函数,收到新连接消息时回调函数被调用。其中,该回调函数自定义设置,它接受三个参数:一个
const TcpConnectionPtr&
(代表连接对象),一个Buffer*
(包含接收到的数据),以及一个Timestamp
(数据到达的时间戳,这里我们不用管)。void setMessageCallback(const MessageCallback& cb);
自定义函数cb如:void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp)
2,EventLoop类接口
// 开始事件监控循环,使EventLoop对象开始监听和处理各种事件。
void loop();
// 退出事件的监控循环
void quit();
// 在指定的时间点执行一个回调函数, 这个回调函数用于在将来的某个确切时间点调度一次性的任务对象。runAfter和runEvery的回调函数同理。
TimerId runAt(Timestamp time, TimerCallback cb);
// 设置一个延时定时器,在指定延迟多少delay毫秒后执行回调函数cb。
TimerId runAfter(double delay, TimerCallback cb);
// 设置一个周期性定时器,每隔指定的时间间隔执行回调函数cb。
TimerId runEvery(double interval, TimerCallback cb);
// 取消定时器。
void cancel(TimerId timerId);
3,TcpConnection类接口
// 发送数据message
void send(string&& message);
void send(const void* message, int len);
void send(const StringPiece& message);
void send(Buffer* message);
// 判断当前连接是否连接正常
bool connected() const
// 关闭连接
void shutdown();
4,TcpClient类接口
// 连接服务器,该接口是非阻塞接口。
// 通常,为了保证连接之间的同步工作,客户端还需要借助一个CountDownLatch类,该类通过计数器将线程阻塞等待,且是线程安全。
void connect();
// 关闭连接
void disconnect();
// 获取客户端对应的TcpConnect连接。由于connect接口是非阻塞操作,所以当发起connect后,有可能还没有成功建立连接
TcpConnectionPtr connection() const;
// 注意:由于客户端也是通过EventLoop类进行IO事件的处理,所以客户端这里也运用setConnectionCallback和setMessageCallback函数
// 连接服务器成功或连接关闭时的回调函数
void setConnectionCallback(ConnectionCallback cb);
// 收到服务器发送的消息时的回调函数
void setMessageCallback(MessageCallback cb);
5,Buffer类接口
// 获取缓冲区可读数据大小
size_t readableBytes() const;
// 获取缓冲区中数据的起始地址
const char* peek() const;
// 从缓冲区中预览4字节数据,但并不从缓冲区删除。网络数据报中,通常前4字节表示数据的长度。这个方法通常用于在解析网络协议时,通过前四字节检查数据是否完整或合格。
int32_t peekInt32() const;
// 数据读取位置向后偏移4字节,本质上就是删除起始位置的4字节数据
void retrieveInt32();
// peekInt32和retrieveInt32功能的合并,即先运行peekInt32,再运行retrieveInt32
int32_t readInt32();
// 从缓冲区取出所有数据作为string返回,并删除缓冲区中的数据
string retrieveAllAsString();
// 从缓冲区取走len长度的数据作为string返回,并删除缓冲区中的数据
string retrieveAsString(size_t len);
4,Muduo库的代码运用
这里我们基于muduo库来实现一个简单英译汉服务器和客户端。
具体代码请在此链接下观看:基于Muduo的英译汉服务的实现
5、Muduo库的工作流程
- 用户创建TcpServer对象,并设置连接建立、消息到达等事件的回调处理函数。
- TcpServer启动后,会创建一个EventLoop对象和一个线程池。主线程运行一个baseLoop(即EventLoop的一个实例),负责监听新的连接请求。
- 当有新的客户端连接请求到来时,baseLoop会调用TcpServer设置的连接建立回调处理函数,将连接请求分发给子线程处理。
- 子线程接收到连接请求后,会创建一个TcpConnection对象来处理该连接的具体事件(如读、写、关闭等)。TcpConnection将读、写、关闭等操作与回调处理函数绑定在一起,并调用EventLoop的相应方法来处理这些事件。
- 底层事件循环中,主线程只执行监听操作与用户回调,而子线程则具体执行操作。
6、特点与优势
- 高性能:Muduo库采用了非阻塞IO和事件循环的设计,能够充分利用多核CPU的性能,实现高效的网络通信。
- 稳定性:Muduo库采用了基于Reactor模式的事件处理机制,即避免了传统多线程模型中的线程竞争和同步问题,又实现了高效率的网络通信。