菏泽网站建设公司蓝希科技,虚拟空间官网,一般网站版式有哪几种,大型网站方案用 muduo 写一个 TCP 服务器基于 epoll 线程池接收客户端连接客户端发什么#xff0c;服务器原样返回#xff08;Echo#xff09;打印连接、断开、收发数据日志muduo 的核心思想#xff1a;网络 I/O 与业务逻辑彻底解耦muduo 的核心模型muduo Reactor One Loop Per Thre…用 muduo 写一个 TCP 服务器基于epoll 线程池接收客户端连接客户端发什么服务器原样返回Echo打印连接、断开、收发数据日志muduo 的核心思想网络 I/O 与业务逻辑彻底解耦muduo 的核心模型muduo Reactor One Loop Per Thread整体结构分析main()└── EventLoop loop // 主 Reactorepoll└── ChatServer server└── TcpServer _server├── ConnectionCallback├── MessageCallback└── 线程池 (setThreadNum)典型 muduo Reactor 模型主线程(EventLoop)||--- 接收新连接|--- 分发连接到子线程(EventLoop)||--- 处理读写事件整体代码/* muduo网络库给用户提供两个主要的类 TcpServer:用户编写服务器程序的 TcpClient:用户编写客户端程序的 epoll 线程池 好处能够把网络I/O的代码和业务代码区分开来 用户的连接与断开 用户的可读写事件 */ #includemuduo/net/TcpServer.h #includemuduo/net/EventLoop.h #includeiostream #includefunctional using namespace std; using namespace muduo; using namespace muduo::net; using namespace placeholders; /*基于muduo网络库开发服务器程序 1.组合TcpSever对象 2.创建EventLoop事件循环对象的指针 3.明确TcpServer构造函数需要什么参数输出ChatServer的构造函数 */ class ChatServer { public: ChatServer(EventLoop * loop,const InetAddress listenAddr,const string nameArg):_server(loop,listenAddr,nameArg),_loop(loop) { _server.setConnectionCallback(bind(ChatServer::onConnection,this,_1)); _server.setMessageCallback(bind(ChatServer::onMessage,this,_1,_2,_3)); //设置EventLoop的线程个数 _server.setThreadNum(10); } //启动ChatServer服务 void start() { _server.start(); } private: //TcpServer绑定的回调函数当有新连接或连接中断时调用 void onConnection(const TcpConnectionPtr conn) { if(conn-connected()) { coutconn-peerAddress().toIpPort() - conn-localAddress().toIpPort()state:onlineendl; } else{ coutconn-peerAddress().toIpPort() - conn-localAddress().toIpPort()state:offlineendl; conn-shutdown();//close(fd) _loop-quit(); } } //TcpServer绑定的回调函数当有新数据时调用 void onMessage(const TcpConnectionPtr conn, Buffer* buffer, Timestamp time) { string bufbuffer-retrieveAllAsString(); coutrecv data:buftime:time.toString()endl; conn-send(buf); } TcpServer _server; EventLoop* _loop; }; int main() { EventLoop loop;//epoll InetAddress addr(127.0.0.1,6000); ChatServer server(loop,addr,ChatServer); server.start();//listen epoll_ctlepoll loop.loop();//epoll_wait以阻塞方式等待新用户连接已连接用户的读写事件等 return 0; }头文件 命名空间#include muduo/net/TcpServer.h #include muduo/net/EventLoop.h #include functional using namespace muduo; using namespace muduo::net; using namespace placeholders;EventLoopReactor 的本体EventLoop loop;EventLoop 是什么EventLoop epoll 事件分发器loop.loop() 在干什么void EventLoop::loop() { while (!quit_) { activeChannels_ poller_-poll(); // epoll_wait for (Channel* ch : activeChannels_) { ch-handleEvent(); } } }为什么 EventLoop 不能拷贝内部持有 fd绑定线程 ID一个 loop 只能在一个线程里跑TcpServerTcpServer 本质是什么TcpServer Acceptor 线程池 连接管理器class TcpServer { EventLoop* loop_; // 主 loop Acceptor acceptor_; // 监听 socket EventLoopThreadPool threadPool_; mapstring, TcpConnectionPtr connections_; };TcpServer 的职责功能谁干accept 新连接Acceptor分配 IO 线程ThreadPool管理连接connections_注册回调setXXXCallbackInetAddress地址封装InetAddress addr(127.0.0.1, 6000);等价于sockaddr_in addr; addr.sin_family AF_INET; addr.sin_port htons(6000); addr.sin_addr.s_addr inet_addr(127.0.0.1);ChatServer 构造函数ChatServer(EventLoop* loop, const InetAddress listenAddr, const string nameArg) : _server(loop, listenAddr, nameArg), _loop(loop)创建 TcpServer内部创建监听 socket但 还没 listen回调机制_server.setConnectionCallback( bind(ChatServer::onConnection, this, _1) );muduo 什么时候调用它✔ accept 成功✔ TCP 连接建立✔ TCP 连接断开TcpConnectionPtrconst TcpConnectionPtr conn等价于shared_ptrTcpConnection为什么一定要 shared_ptr连接可能正在读正在写正在关闭防止提前析构保证回调执行期间对象存在这是 muduo 稳定性的核心设计setMessageCallback_server.setMessageCallback( bind(ChatServer::onMessage, this, _1, _2, _3) );什么时候触发socket fd EPOLLINonMessage 参数拆解const TcpConnectionPtr conn Buffer* buffer Timestamp timeBuffer 是什么muduo 的用户态缓冲区socket → kernel buffer → Buffer → 用户Timestamptime.toString() 消息到达服务器的时间 muduo 在 epoll 返回时打的时间戳send()conn-send(buf);send 是怎么做到非阻塞的尝试 write写不完 → 放入 output buffer注册 EPOLLOUT可写时继续写main 函数执行全过程mainEventLoop loopChatServer serverserver.start()├ socket()├ bind()├ listen()├ 创建线程池loop.loop()└ epoll_wait (阻塞)