目录
3、明确TCPServer构造函数需要的参数,输出ChatServer的构造函数
4、在当前服务器类的构造函数当中,注册处理连接的回调函数和处理读写事件的回调函数
5、设置合适的服务端线程数量,muduo库会自己分配I/O线程和work线程
今天开始,小鱼将和大家一起学习陈硕大佬的优秀开源项目------muduo网络库,并重写muduo网络库的一些重要的函数、类等代码,学习优秀的开源代码和编码思维。
在学习muduo网络库之前,我们首先要知道muduo库如何使用,今天,我们一起来用muduo库写一下简单的服务器和客户端的代码,并测试一下。
首先,我们要知道muduo网络库提供了两个重要的类
TcpServer:用于编写服务器程序
TCPClient:用于编写客户端程序
mudou网络库使用了epoll+线程池,这样的做的好处是可以把网络I/O的代码和业务代码区分开。
接下来,我们就开始用muduo网络库编写代码。
- EventLoop* loop, //事件循环
- const InetAddress &listenAddr, //IP+Port
- const string &nameArg //服务器的名字
这里的EventLoop *loop就是事件循环,也可以理解为reactor模型的反应堆。const InetAddress &listenAddr表示服务器的端口,const string &nameArg 指的是服务器的名字,也就是给线程绑定一个名字。
- class ChatServer{
- public:
- ChatServer(EventLoop* loop, //事件循环
- const InetAddress &listenAddr, //IP+Port
- const string &nameArg) //服务器的名字
- : _server(loop, listenAddr, nameArg), _loop(loop)
- {
- //给服务器注册用户连接的创建和断开回调
- _server.setConnectionCallback(std::bind(&ChatServer::onConnection,this,_1));
-
- //给服务器注册用户读写时间回调
- _server.setMessageCallback(std::bind(&ChatServer::onMessage, this,_1,_2,_3));
-
- //设置服务器端的线程数量,1个IO线程,3个work线程
- _server.setThreadNum(4);
- }
-
- //开启事件循环
- void start(){
- _server.start();
- }
这里的setConnectionCallback(std::bind(&ChatServer::onConnection,this,_1))函数绑定了onConnection的this。当底层监测到有用户的连接和断开的时候就会帮我们调用这个函数,给服务器注册用户连接的创建和断开回调。
下面的setMessageCallback(std::bind(&ChatServer::onMessage, this,_1,_2,_3))函数也是同样的意思。
- //专门处理用户的连接创建和断开 epoll listenfd accept
- void onConnection(const TcpConnectionPtr &conn){
-
- if(conn->connected()){
- cout << conn->peerAddress().toIpPort() << "->" <<
- conn->localAddress().toIpPort() << "state:online" << endl;
- }
- else{
- cout << conn->peerAddress().toIpPort() << "->" <<
- conn->localAddress().toIpPort() << "state:offline" << endl;
- conn->shutdown(); //close(fd)
- //_loop->quit(); 连接断开
- }
- }
这是专门处理用户的连接创建和断开的函数。
- //专门处理用户读写事件
- void onMessage(const TcpConnectionPtr &conn, //连接
- Buffer *buffer, //缓冲区
- Timestamp time) //接收到数据的时间信息
- {
- string buf = buffer->retrieveAllAsString();
- cout << "recv data:" << buf << "time:" << time.toString() << endl;
- conn->send(buf);
- }
这是专门处理用户读写事件的函数。
- //设置服务器端的线程数量,1个IO线程,3个work线程
- _server.setThreadNum(4);
设置服务器端的线程数量,1个IO线程,3个worker线程
第一个工作线程做耗时的I/O操作,主要是传输文件、音视频等二进制文件的操作;
第二个线程处理已连接事件的读写事件;
第三个线程处理用户的连接和断开;
- #include
- #include
- #include
- #include
- #include
- using namespace std;
- using namespace muduo;
- using namespace muduo::net;
-
- /*基于muduo网络库开发服务器程序
- 1、组合TcpServer对象
- 2、创建EventLoop事件循环对象的指针
- 3、明确TCPServer构造函数需要什么参数,输出ChatServer的构造函数
- 4、在当前服务器类的构造函数当中,注册处理连接的回调函数和处理读写事件的回调函数
- 5、设置合适的服务端线程数量,muduo库会自己分配I/O线程和work线程
- */
- class ChatServer{
- public:
- ChatServer(EventLoop* loop, //事件循环
- const InetAddress &listenAddr, //IP+Port
- const string &nameArg) //服务器的名字
- : _server(loop, listenAddr, nameArg), _loop(loop)
- {
- //给服务器注册用户连接的创建和断开回调
- _server.setConnectionCallback(std::bind(&ChatServer::onConnection,this,_1));
-
- //给服务器注册用户读写时间回调
- _server.setMessageCallback(std::bind(&ChatServer::onMessage, this,_1,_2,_3));
-
- //设置服务器端的线程数量,1个IO线程,3个work线程
- _server.setThreadNum(4);
- }
-
- //开启事件循环
- void start(){
- _server.start();
- }
- private:
- //专门处理用户的连接创建和断开 epoll listenfd accept
- void onConnection(const TcpConnectionPtr &conn){
-
- if(conn->connected()){
- cout << conn->peerAddress().toIpPort() << "->" <<
- conn->localAddress().toIpPort() << "state:online" << endl;
- }
- else{
- cout << conn->peerAddress().toIpPort() << "->" <<
- conn->localAddress().toIpPort() << "state:offline" << endl;
- conn->shutdown(); //close(fd)
- //_loop->quit(); 连接断开
- }
- }
-
- //专门处理用户读写事件
- void onMessage(const TcpConnectionPtr &conn, //连接
- Buffer *buffer, //缓冲区
- Timestamp time) //接收到数据的时间信息
- {
- string buf = buffer->retrieveAllAsString();
- cout << "recv data:" << buf << "time:" << time.toString() << endl;
- conn->send(buf);
- }
-
-
- TcpServer _server; //#1
- EventLoop *_loop; //#2 epoll
- };
-
- int main(){
- EventLoop loop; //epoll
- InetAddress addr("192.168.18.128",6000);
- ChatServer server(&loop, addr, "ChatServer");
-
- server.start(); //listenfd epoll_ctl=>epoll
- loop.loop(); //epoll_wait以阻塞的方式等待新用户的连接,已连接的用户读写事件等
-
- return 0;
- }
运行一下

