一、muduo網絡庫主要提供了兩個類:
????????TcpServer:用于編寫服務器程序????????
????????TcpClient:用于編寫客戶端程序
二、三個重要的鏈接庫:
????????libmuduo_net、libmuduo_base、libpthread
三、muduo庫底層就是epoll+線程池,其好處是:
????????可以將網絡I/O代碼和業務代碼區分開,用戶只需關注業務,網絡的連接斷開、讀寫事件的上報與監控交給muduo庫
四、muduo庫對外暴露兩個業務接口:
? ? ? ? 1.用戶的連接與斷開
? ? ? ? 2.用戶的可讀寫事件
五、基于muduo網絡庫的服務器開發步驟
????????1.組合TcpServer對象
????????2.創建Eventloop事件循環對象的指針
????????3.明確Tcpserver構造函數需要什么參數,輸出Chatserver的構造函數
? ? ????????a.Tcpserver 主要提供兩個回調函數:setConnectionCallback與setMessageCallback
? ? ????????b.在構造函數中定義回調函數,在類中定義具體回調的函數的實現
????????4.在當前服務類的構造函數中,注冊處理連接的回調函數和處理讀寫事件的回調函數
????????5.設置合適的服務端線程數量,muduo庫會自己分配I/O線程和work線程
/*
muduo網絡庫主要提供了兩個類:TcpServer:用于編寫服務器程序
TcpClient:用于編寫客戶端程序三個重要的鏈接庫:
libmuduo_net、libmuduo_base、libpthreadmuduo庫底層就是epoll+線程池,其好處是:
可以將網絡I/O代碼和業務代碼區分開,用戶只需關注業務,網絡的連接斷開、讀寫事件的上報與監控交給muduo庫只暴露兩個業務接口:
1.用戶的連接與斷開
2.用戶的可讀寫事件*/
#include<muduo/net/TcpServer.h>
#include<muduo/net/EventLoop.h>
#include<functional>// #bind
#include<iostream>
#include<string>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;/*
基于muduo網絡庫的服務器開發
1.組合TcpServer對象
2.創建Eventloop事件循環對象的指針
3.明確Tcpserver構造函數需要什么參數,輸出Chatserver的構造函數a.Tcpserver 主要提供兩個回調函數:setConnectionCallback與setMessageCallbackb.在構造函數中定義回調函數,在類中定義具體回調的函數的實現
4.在當前服務類的構造函數中,注冊處理連接的回調函數和處理讀寫事件的回調函數
5.設置合適的服務端線程數量,muduo庫會自己分配I/O線程和work線程*/
class ChatServer{
public://構造函數對TcpServer進行初始化,TcpServer沒有默認構造ChatServer(EventLoop *loop,//事件循環 reactorconst InetAddress &listenAddr,//ip + portconst string &nameArg)// 線程/server的名稱: _server(loop, listenAddr, nameArg), _loop(loop){//給服務器注冊用戶連接與斷開的回調函數,當監聽到連接/斷開時執行onConnection,具體如何監聽到是網絡庫的事情,無需用戶操心_server.setConnectionCallback(std::bind(&ChatServer::onConnection,this,_1));//相當于this.onConnection(TcpConnectionPtr&)//給服務器注冊用戶讀寫事件的回調函數_server.setMessageCallback(std::bind(&ChatServer::onMessage,this,_1,_2,_3));//設置服務器端的線程數量,muduo庫會自適應處理連接線程和工作線程的分配;CPU核數一般等于線程數//1個I/O線程,3個work線程_server.setThreadNum(4);}//開啟事件循環void start(){_server.start();}private://專門處理用戶的連接創建和斷開,相當于epoll中監聽到listenfd后執行acceptvoid 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)}}//專門處理用戶的讀寫事件void onMessage(const TcpConnectionPtr &conn,//連接的共享指針Buffer *buffer,//緩沖區,存放數據Timestamp time)//接收到數據的時間信息{//echo服務器string buf=buffer->retrieveAllAsString();cout<<"recv: "<<buf<<"time: "<<time.toString()<<endl;conn->send(buf);}TcpServer _server;// #1EventLoop *_loop;// #2 看作epoll};int main(){EventLoop loop;//類似于創建epollInetAddress addr("127.0.0.1",6000);//本地回環地址,服務器僅接受來自本機的連接。適合在開發階段進行本地調試。ChatServer server(&loop,addr,"ChatServer");server.start();//epoll_ctl,listenfd加入epollloop.loop();//類似于epoll_wait,以阻塞的方式等待新用戶連接,已連接用戶的讀寫事件等return 0;
}
結果展示: