首页 > 其他分享 >【muduo】net篇---TcpServer

【muduo】net篇---TcpServer

时间:2023-08-29 12:33:20浏览次数:30  
标签:muduo TcpConnection TcpServer --- _- loop net conn Acceptor


TcpServer在创建的过程中,首先new出来自己的核心组件(Acceptor,loop,connectionMap,threadPool)之后TcpServer会向Acceptor注册一个新连接到来时的Connection回调函数。一旦接受到一个client的连接,就会调用TcpServer::newConnection()函数。这个函数使用round-robin算法从EventLoopThreadPool中选择一个EventLoop,并创建一个TcpConnection对象,设置回调函数,参数来源于TcpServer。

#include <muduo/net/TcpServer.h>
#include <muduo/base/Logging.h>
#include <muduo/net/Acceptor.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/EventLoopThreadPool.h>
#include <muduo/net/SocketsOps.h>

#include <stdio.h>

using namespace muduo;
using namespace muduo::net;

/******************************************************************** 
Modify : Eric Lee
Date : 2018-01-15 
Description : 创建一个TcpServer对象,在的创建过程中,首先new出来
自己的核心组件(Acceptor,loop,connectionMap,threadPool)之后
TcpServer会向Acceptor注册一个新连接到来时的Connection回调函数。
loop是由用户提供的,并且在最后向Acceptor注册一个回调对象,
用于处理:一个新的Client连接到来时该怎么处理。
*********************************************************************/
TcpServer::TcpServer(EventLoop* loop,
                     const InetAddress& listenAddr,
                     const string& nameArg,
                     Option option)
  : loop_(CHECK_NOTNULL(loop)),
    ipPort_(listenAddr.toIpPort()),
    name_(nameArg),
    acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),
    threadPool_(new EventLoopThreadPool(loop, name_)),
    connectionCallback_(defaultConnectionCallback),
    messageCallback_(defaultMessageCallback),
    nextConnId_(1)
{
  // 注册给acceptor的回调
  acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, _1, _2));
}

TcpServer::~TcpServer()
{
  loop_->assertInLoopThread();
  LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing";
  for (auto& item : connections_)
  {
    TcpConnectionPtr conn(item.second);
    item.second.reset();
    conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
  }
}

/******************************************************************** 
Modify : Eric Lee
Date : 2018-01-17
Description : 设置eventloop线程池中线程的数量。
*********************************************************************/
void TcpServer::setThreadNum(int numThreads)
{
  assert(0 <= numThreads);
  threadPool_->setThreadNum(numThreads);
}

/******************************************************************** 
Modify : Eric Lee
Date : 2018-01-17
Description : 启动服务器。
*********************************************************************/
void TcpServer::start()
{
  if (started_.getAndSet(1) == 0)
  {
    // 对线程池的一个启动处理
    threadPool_->start(threadInitCallback_);
    // 打开Acceptor的监听状态
    assert(!acceptor_->listenning());
    loop_->runInLoop(std::bind(&Acceptor::listen, get_pointer(acceptor_)));
  }
}

/******************************************************************** 
Modify : Eric Lee
Date : 2018-01-17
Description : 
这个函数实际上是对accpet新接受到一个通信套接字以后把它放入到一个
新创立的TcpConnection对这个通信套接字做一个封装,并将函数指针初始化,
它调用了TcpConnection::connectEstablished这个函数,这个函数的作用
就是将接受到的socket的文件描述符注册到epoll事件列表当中。

换言之:

主线程在EventLoop::loop() 中不停查询可用的I/O. 当一个新的tcp连接
到来时,Channel::handleEventWithGuard 会调用Acceptor::handleRead, 
然后回调TcpServer::newConnection()。
*********************************************************************/
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
  // 断言是否在IO线程
  loop_->assertInLoopThread();
  // 从线程池中取出一个EventLoop对象(轮流取,负载均衡),然后把该链接交给它管理,
  // 如果线程池的线程数量为0,那么将返回基础的EventLoop即loop(Acceptor的EventLoop)
  EventLoop* ioLoop = threadPool_->getNextLoop();
  char buf[64];
  snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);
  ++nextConnId_;
  string connName = name_ + buf;
  LOG_INFO << "TcpServer::newConnection [" << name_
           << "] - new connection [" << connName
           << "] from " << peerAddr.toIpPort();
  InetAddress localAddr(sockets::getLocalAddr(sockfd));
  // 根据ioLoop, connName, sockfd, localAddr, peerAddr构建一个新的TcpConnection
  // 当accept接受到一个新的文件描述符的时候,创建一个TcpConnection对它进行封装
  TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));
  // 将新构建的conn加入ConnectionMap中
  connections_[connName] = conn;
  // 对新建立的TcpConnection进行初始化(参数来源于TcpServer,而TcpServer的参数则是由用户提供的)
  conn->setConnectionCallback(connectionCallback_);
  conn->setMessageCallback(messageCallback_);
  conn->setWriteCompleteCallback(writeCompleteCallback_);
  conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, _1));
  ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}

void TcpServer::removeConnection(const TcpConnectionPtr& conn)
{
  loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}

/******************************************************************** 
Modify : Eric Lee
Date : 2018-01-17
Description : 
移除TcpConnection,注册到TcpServer::removeConnectionInLoop上。
*********************************************************************/
void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn)
{ 
  loop_->assertInLoopThread();
  LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ << "] - connection " << conn->name();
  // 删除该conn(一个map对象)
  size_t n = connections_.erase(conn->name());
  (void)n;
  // conn的引用计数变为1
  assert(n == 1);
  // 获得本线程的Loop
  EventLoop* ioLoop = conn->getLoop();
  // 调用TcpConnection::connectDestroyed销毁连接
  ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}


标签:muduo,TcpConnection,TcpServer,---,_-,loop,net,conn,Acceptor
From: https://blog.51cto.com/u_6526235/7274961

相关文章

  • 【muduo】net篇---EventLoop
    EventLoop类调用Poller::poll()进行I/O复用,返回活跃事件列表,然后遍历该列表,依次调用每一个活跃Channel的事件处理函数handleEvent(),最终回调了TcpConnection注册过来的函数。#include<muduo/net/EventLoop.h>#include<muduo/base/Logging.h>#include<muduo/base/Mutex.h>#inc......
  • 【muduo】net篇---Poller
    Poller类负责更新某一个Channel(或者说套接字)上对应的事件,通过epoll_wait()函数返回有事件发生的套接字,设置Channel上的事件(revents_),并添加到激活事件列表中。#include<muduo/net/poller/EPollPoller.h>#include<muduo/base/Logging.h>#include<muduo/net/Channel.h>#include......
  • 【muduo】常见的并发网络服务程序设计方案
    文章目录一、IO复用1、select模型2、poll模型3、epoll模型二、单线程Reactor三、Reactor+ThreadPool四、MultipleReactors(oneloopperthread)一、IO复用目前常用的IO复用模型有三种:select,poll,epoll。1、select模型说的通俗一点就是各个客户端连接的文件描述符也就是套接字,都......
  • 【muduo】TCP分包和Buffer类的设计
    文章目录一、TCP分包问题1、长连接和短连接2、长连接和短连接的分包方法3、长连接和短连接的应用场景二、TCP粘包问题三、Buffer类的设计与使用1、为什么需要应用层buffer?2、如何设计并使用应用层Buffer?3、Buffer类的设计一、TCP分包问题在TCP这种字节流协议上做应用层分包是网络......
  • 论文阅读 《Pingmesh: A Large-Scale System for Data Center Network Latency Measur
    背景在我们内部产品中,一直有关于网络性能数据监控需求,我们之前是直接使用ping命令收集结果,每台服务器去ping(N-1)台,也就是N^2的复杂度,稳定性和性能都存在一些问题,最近打算对这部分进行重写,在重新调研期间看到了Pingmesh这篇论文,Pingmesh是微软用来监控数据中心网络情况......
  • 2023年DAMA-CDGA/CDGP数据治理认证线上到这里学习
    DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义,帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力,促进开展工作实践应用及实际问题解决,形成企业所需的新数字经济下的核心职业竞争能力。DAMA是数据管理方面的认证,帮助数据从业者提升......
  • 2023年9月DAMA-CDGA/CDGP数据治理认证考试,火热报名
    据DAMA中国官方网站消息,2023年度第三期DAMA中国CDGA和CDGP认证考试定于2023年9月23日举行。 报名通道现已开启,相关事宜通知如下: 考试科目: 数据治理工程师(CertifiedDataGovernanceAssociate,CDGA)数据治理专家(CertifiedDataGovernanceProfessional,CDGP) 考试时间: CDGA:2023......
  • iTOP-i.MX8MM开发板添加RIL驱动程序库
    将Quectel提供的相应RIL库文件放入Android系统的以下路径。作者拷贝到了源码的android_build/device/fsl/imx8m/evk_8mm/lib目录下,如下图所示:然后将apns-conf.xml拷贝到android_build/device/fsl/imx8m/evk_8mm/下,如下图所示:......
  • 智能菜谱系统-计算机毕业设计源码+LW文档
    1.1研究背景自古以来,烹饪食品一直是人类的基本需求之一,烹饪技术的不断发展和创新,为人们带来了不同的美食体验。科技进步的同时又在不断地加快人们的生活节奏,越来越忙碌的生活节奏使得人们能够花费在制作美食上的时间越来越少;同时,随着生活水平的提高,人们对健康饮食的需求也日益增长......
  • 幼儿园管理系统-计算机毕业设计源码+LW文档
    摘 要现在人们对学前教育越来越重视,幼儿教育发展迅速,幼儿的数量也在大大增加,导致幼儿园的管理工作变得愈加繁重。以报表的方式管理幼儿园信息资料,不仅不方便园中资料的存储和查看,还加重了园中的管理工作、减低了工作效率。现在,大多数幼儿园都缺少一个向外界展现自身特色的平台,幼......