1、 首先在主线程中创建一个EventLoop类型的对象mainLoop,该EventLoop对象会默认创建一个Poller类型的对象mainPoller,该Poller对象包含一个vector(vector<struct pollfd>)和一个map(map<fd, Channel>);
2、 创建一个TcpServer对象,并将刚才创建的mainLoop对象以及需要监听的端口号传入
TcpServer会创建如下对象:
1) 创建一个Acceptor对象,并将mainLoop对象和要监听的端口号传入,Acceptor对象会根据本地IP和传入的端口号创建一个socket对象,然后根据创建socket返回的fd创建一个Channel对象,并将该mainLoop传给该Channel对象,此时该channel就可以通过mainLoop插入到mainPoller的vector和map中;
2) 创建一个线程池对象,线程池对象创建N个EventLoopThread对象,EventLoopThread会创建一个thread对象,并在该thread对象中创建一个EventLoop类型的对象subLoop,每个subLoop对象又会默认创建一个Poller类型的对象subPoller,每个subPoller对象包含一个vector(vector<struct pollfd>)和一个map(map<fd, Channel>);
线程池持有两个vector(vector<EventLoopThread>和vector<subLoop>);
3) 每当Acceptor对象收到一个新的连接时,创建一个TcpConnection对象,从线程池对象中获取一个subLoop对象,并将接收到的连接的fd和该subLoop对象传入,TcpConnection对象会创建一个Channel对象,并将刚才的fd和subLoop对象传入,此时该Channel对象就会通过subLoop对象插入到subPoller的vector和map中;
4) 创建一个map(map<connName, TcpConnection>),每当收到一个新的连接时都会插入到该map中,每当关闭一个连接时,都会从该map中移出,插入和移出的操作都是在mainLoop中执行;
3、 启动TcpServer对象,这个过程会启动线程池,并会启动Acceptor对象开始监听;
4、 启动mainLoop;
由此可见:
1) TcpServer对象的创建,以及它内部的Acceptor对象、线程池对象、TcpServer都是在主线程中,在mainLoop的loop执行之前进行的
2) Acceptor对象的所有操作都是在mainLoop的loop函数中进行的,TcpConnection对象的创建,插入和移出TcpServer的map,也是在mainLoop的loop函数中进行
3) TcpConnection对象对于读写事件的处理,连接的建立和关闭都是在subLoop的loop函数中处理的
代码示例如下:
void onConnection(const muduo::TcpConnectionPtr& conn)
{
if (conn->connected())
{
conn->send(message);
}
}
void onWriteComplete(const muduo::TcpConnectionPtr& conn)
{
conn->send(message);
}
void onMessage(const muduo::TcpConnectionPtr& conn, muduo::Buffer* buf, muduo::Timestamp receiveTime)
{
printf("onMessage(): received\n",);
buf->retrieveAll();
}
int main(int argc, char* argv[])
{
muduo::EventLoop loop;
muduo::InetAddress listenAddr(9981);
muduo::TcpServer server(&loop, listenAddr);
server.setConnectionCallback(onConnection);
server.setMessageCallback(onMessage);
server.setWriteCompleteCallback(onWriteComplete);
if (argc > 1) {
server.setThreadNum(atoi(argv[1]));
}
server.start();
loop.loop();
}
网友评论