库安装
Muduo库和boost库安装参考:Linux平台下muduo网络库源码编译安装
Muduo库简介
muduo库线程模型采用sub-Reactor模式,采用nonblock io + one loop per thread 以及 epoll + 线程池
muduo网络库给用户提供了两个主要的类
-
TcpServer
-
TcpClient
muduo库的优点
把网络IO代码和业务代码分开
实现了用户的连接和断开 与 用户的可读写事件处理的解耦。
程序员只需集中精力于onMessage
和 onConnection
函数进行业务处理
muduo库开发服务器程序基本步骤
- 组合TcpServer对象
- 创建EventLoop事件循环对象的指针(相当于epoll)
- 明确TcpServer构造函数需要什么参数,输出ChatServer构造
- 在当前服务器类的构造函数中,注册处理连接的回调函数和处理读写事件的回调函数
- 设置合适的服务端线程数量,muduo会自己划分I/O线程和worker线程
使用实例
用muduo库实现一个回声服务器
// muduo_server.cpp
#include <muduo/net/TcpServer.h>
#include <muduo/base/Logging.h>
#include <functional>
#include <muduo/net/EventLoop.h>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;
class EchoServer
{
public:
EchoServer(EventLoop *loop, // 事件循环
const InetAddress &listenAddr, // IP Port
const string &nameArg) // 服务器名字
: _server(loop, listenAddr, nameArg), _loop(loop)
{
// 给服务器注册用户连接和断开的回调
_server.setConnectionCallback(std::bind(&EchoServer::onConnection, this, _1));
// 给服务器注册用户读写事件的回调
_server.setMessageCallback(std::bind(&EchoServer::onMessage, this, _1, _2, _3));
// 设置服务端的线程数量,内部分一个给IO线程,其他为业务处理线程
// 1个IO线程,3个Worker线程
_server.setThreadNum(4);
}
// 开启事件循环
void start()
{
_server.start();
}
private:
// 专门处理用户的连接创建和断开 epoll listenfd accept
void onConnection(const TcpConnectionPtr &conn)
{
LOG_INFO << conn->peerAddress().toIpPort() << " -> "
<< conn->localAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");
}
// 专门处理用户的读写事件
void onMessage(const TcpConnectionPtr &conn, // 连接
Buffer *buf, // 缓冲区
Timestamp time) // 时间戳
{
muduo::string msg(buf->retrieveAllAsString());
LOG_INFO << conn->name() << " echo " << msg.size() << "bytes, "
<< "data recived at " << time.toString();
conn->send(msg); // echo
}
TcpServer _server; // #1 采用组合而非继承
EventLoop *_loop; // #2 epoll
};
int main()
{
EventLoop loop; // epoll
InetAddress addr("127.0.0.1", 6000);
EchoServer server(&loop, addr, "EchoServer");
server.start(); // listen , 将listenfd传入epoll_ctl,上epoll内核事件表
loop.loop(); // epoll_wait 阻塞方式等待新用户连接,或已连接用户的读写事件
return 0;
}
编译调试
g++ -o server muduo_server.cpp -lmuduo_net -lmuduo_base -lpthread
-lmuduo_net -lmuduo_base -lpthread连接动态库顺序不能颠倒,因为-lmuduo_net 需要依赖 -lmuduo_base, 而前面两个库都需要依赖-lpthread
客户端
服务端