在此之前,我们对于muduo库的每一类几乎都进行了逐行的分析,但是一个网络库的每个模块之间总是有千丝万缕的关系,所以可能有的地方还是有分析的不到位,所以从这一篇开始,我们从muduo的简单使用----搭建一个Echo服务器,来一步一步的分析一下整个muduo库的内在联系。
TCP网络编程最本质是的处理三个半事件
连接建立:服务器accept(被动)接受连接,客户端connect(主动)发起连接
连接断开:主动断开(close、shutdown),被动断开(read返回0)
消息到达:客户端文件描述符可读
消息发送完毕:这算半个。对于低流量的服务,可不必关心这个事件;这里的发送完毕是指数据写入操作系统缓冲区,将由TCP协议栈负责数据的发送与重传,不代表对方已经接收到数据。
接下来,我们从这几个事件来梳理整个muduo库。
搭建Echo服务器
在学习一个网络库之前,我们一定是要先学会怎么使用这个网络库,接下来,我们搭建一个最简单的Echo服务器。
什么是Echo服务器
echo服务器,也称为回显服务器,简单来说就是服务端收到什么,就给客户端发送什么。
源码
#include <my_muduo/TcpServer.h>
#include <my_muduo/logger.h>
#include <string>
#include <functional>
class EchoServer
{
public:
EchoServer(EventLoop *loop,
const InetAddress &addr,
const std::string &name)
:server_(loop,addr,name)
,loop_(loop)
{
//注册回调函数
server_.setConnectionCallback(
std::bind(&EchoServer::onConnection,this,std::placeholders::_1)
);
server_.setMessageCallback(
std::bind(&EchoServer::onMessage,this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
);
//设置合适的loop线程数量 loopThread
server_.setThreadNum(3);
}
void start()
{
server_.start();
}
private:
//连接建立或者断开的回调
void onConnection(const TcpConnectionPtr &conn)
{
if(conn->connected())
{
LOG_INFO("Connection UP : %s",conn->peerAddress().toIpPort().c_str());
}
else
{
LOG_INFO("Connection DOWN : %s",conn->peerAddress().toIpPort().c_str());
}
}
//可读写事件回调
void onMessage(const TcpConnectionPtr &conn,
Buffer *buf,
TimeStamp time)
{
std::string msg = buf->retrieveAllAsString();
conn->send(msg);
conn->shutdown(); //关闭写端EPOLLHUP=> closeCallback
}
EventLoop *loop_;
TcpServer server_;
};
int main()
{
EventLoop loop;
InetAddress addr(8000);
//Acceptor non-blocking listenfd create bind
EchoServer server(&loop,addr,"EchoServer-01");
//listen loopthread listenfd => acceptChannel => mainLoop => subloop
server.start();
loop.loop(); //启动mainloop的底层pooler
return 0;
}
从代码中,我们可以看出来它一共做了如下几件事:
- 创建了一个EventLoop:
EventLoop loop;
,这个EventLoop就是mainLoop,loop就是baseloop_
; - 指定了接收端口号,ip使用默认的127.0.0.1;
- 创建了一个server对象,即TcpServer类对象 :
TcpServer server_;
,并传入了loop,addr,以及指定了对象名; - 启动TcpServer服务器,
server.start();
,调用TcpServer::start()
; - 开启事件循环:
loop.loop();
,调用EventLoop::loop()
。
代码地址:https://github.com/Cheeron955/mymuduo/tree/master