【muduo】net篇---TcpServer

  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));
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~青萍之末~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值