TcpServer拥有Acceptor类,新连接到达时new TcpConnection后续客户端和TcpConnection类交互。TcpServer管理连接和启动线程池,用Acceptor接受连接。

// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#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>  // snprintfusing namespace muduo;
using namespace muduo::net;TcpServer::TcpServer(EventLoop* loop,const InetAddress& listenAddr,const string& nameArg,Option option): loop_(CHECK_NOTNULL(loop)), //TcpServer所在的主线程下运行的事件驱动循环ipPort_(listenAddr.toIpPort()),/* 服务器负责监听的本地ip和端口 */name_(nameArg),/* 服务器名字,创建时传入 */acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),/* Acceptor对象,负责监听客户端连接请求,运行在主线程的EventLoop中 */threadPool_(new EventLoopThreadPool(loop, name_)),/* 事件驱动线程池,池中每个线程运行一个EventLoop */connectionCallback_(defaultConnectionCallback),/* 用户传入,有tcp连接到达或tcp连接关闭时调用,传给TcpConnection */messageCallback_(defaultMessageCallback),/* 用户传入,对端发来消息时调用,传给TcpConnection */nextConnId_(1) /* TcpConnection特有id,每增加一个TcpConnection,nextConnId_加一 */
{ /* * 设置回调函数,当有客户端请求时,Acceptor接收客户端请求,然后调用这里设置的回调函数* 回调函数用于创建TcpConnection连接*/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));}
}void TcpServer::setThreadNum(int numThreads)
{assert(0 <= numThreads);threadPool_->setThreadNum(numThreads);
}void TcpServer::start()
{if (started_.getAndSet(1) == 0){threadPool_->start(threadInitCallback_);//启动线程池,threadInitCallback_创建好所有线程后调用的回调函数assert(!acceptor_->listenning());loop_->runInLoop(       //直接调用linsten函数std::bind(&Acceptor::listen, get_pointer(acceptor_)));}
}/* * Acceptor接收客户端请求后调用的回调函数* @param sockfd: 已经接收完成(三次握手完成)后的客户端套接字* @param peerAddr: 客户端地址* * Acceptor只负责接收客户端请求* TcpServer需要生成一个TcpConnection用于管理tcp连接* * 1.TcpServer内有一个EventLoopThreadPool,即事件循环线程池,池子中每个线程都是一个EventLoop* 2.每个EventLoop包含一个Poller用于监听注册到这个EventLoop上的所有Channel* 3.当建立起一个新的TcpConnection时,这个连接会放到线程池中的某个EventLoop中* 4.TcpServer中的baseLoop只用来检测客户端的连接* * 从libevent的角度看就是* 1.EventLoopThreadPool是一个struct event_base的池子,池子中全是struct event_base* 2.TcpServer独占一个event_base,这个event_base不在池子中* 3.TcpConnection会扔到这个池子中的某个event_base中*/
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{loop_->assertInLoopThread();EventLoop* ioLoop = threadPool_->getNextLoop();//从事件驱动线程池中取出一个线程给TcpConnection /* 为TcpConnection生成独一无二的名字 */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();/* * 根据sockfd获取tcp连接在本地的<地址,端口>* getsockname(int fd, struct sockaddr*, int *size);*/InetAddress localAddr(sockets::getLocalAddr(sockfd));// FIXME poll with zero timeout to double confirm the new connection// FIXME use make_shared if necessary/* 创建一个新的TcpConnection代表一个Tcp连接 */TcpConnectionPtr conn(new TcpConnection(ioLoop,connName,sockfd,localAddr,peerAddr));/* 添加到所有tcp 连接的map中,键是tcp连接独特的名字(服务器名+客户端<地址,端口>) */connections_[connName] = conn;/* 为tcp连接设置回调函数(由用户提供) */conn->setConnectionCallback(connectionCallback_);conn->setMessageCallback(messageCallback_);conn->setWriteCompleteCallback(writeCompleteCallback_);/* * 关闭回调函数,由TcpServer设置,作用是将这个关闭的TcpConnection从map中删除* 当poll返回后,发现被激活的原因是EPOLLHUP,此时需要关闭tcp连接* 调用Channel的CloseCallback,进而调用TcpConnection的handleClose,进而调用removeConnection*/conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe/* * 连接建立后,调用TcpConnection连接建立成功的函数* 1.新建的TcpConnection所在事件循环是在事件循环线程池中的某个线程* 2.所以TcpConnection也就属于它所在的事件驱动循环所在的那个线程* 3.调用TcpConnection的函数时也就应该在自己所在线程调用* 4.所以需要调用runInLoop在自己的那个事件驱动循环所在线程调用这个函数* 5.当前线程是TcpServer的主线程,不是TcpConnection的线程,如果在这个线程直接调用会阻塞监听客户端请求* 6.其实这里不是因为线程不安全,即使在这个线程调用也不会出现线程不安全,因为TcpConnection本就是由这个线程创建的*/ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}void TcpServer::removeConnection(const TcpConnectionPtr& conn)
{// FIXME: unsafeloop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn)
{//关闭连接,把fd从epoll中del掉,要释放connector(包括描述符)和channelloop_->assertInLoopThread();LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_<< "] - connection " << conn->name();size_t n = connections_.erase(conn->name());(void)n;assert(n == 1);EventLoop* ioLoop = conn->getLoop();ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}

不多说

muduo之TcpServer相关推荐

  1. muduo网络库之Acceptor、TcpServer

    本篇博客针对Acceptor类和TcpServer类做下小结. 博客代码来自于陈硕的muduo网络库,github地址https://github.com/chenshuo/muduo 学习笔记: A ...

  2. muduo源码分析——TcpServer和Acceptor

    这篇文章用于分析muduo的TcpServer类和Acceptor类,原本打算将TcpConnection也放到这里一起聊的,但是那个太多啦,一篇文章太长会让人读的很不舒服把. 当然我用的代码是其他大 ...

  3. Muduo 网络编程示例之四:Twisted Finger

    陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 这是<Muduo 网络编程示例>系列的第四篇文章. Muduo 全系列文章列表: http:/ ...

  4. Muduo 网络编程示例之三:定时器

    陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 这是<Muduo 网络编程示例>系列的第三篇文章. Muduo 全系列文章列表: http:/ ...

  5. muduo实现finger服务

    (一)finger服务简介 1.1基本概念 finger(端口79)是互连网上最古老的协议之一, 用于提供站点及用户的基本信息, 一般通过finger服务,你可以查询到站点上的在线用户清单及其他一些有 ...

  6. Muduo 网络编程示例之十:socks4a 代理服务器

    Muduo 网络编程示例之十:socks4a 代理服务器 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice  t.sina.com.cn/giantchen ...

  7. 学习Muduo中ChatRoom实现的各种细节和思考

    Muduo中ChatRoom 1.长连接中的分包解决 固定消息长度, 比如说固定消息长度是16字节 使用特殊的字符作为分割符号,比如说 HTTP协议中的\r\n作为头部的分割符 每个消息头部加上长度字 ...

  8. muduo如何从0到1

    muduo入门 文章目录 muduo入门 如何使用muduo echo 服务器 总结 如何使用muduo muduo作为是木铎的拼音.木铎是铎的一种.中国古代用以警众的响器. 从GitHub下载mud ...

  9. Muduo 网络编程示例之零:前言

    陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice Muduo 全系列文章列表: http://blog.csdn.net/Solstice/category ...

最新文章

  1. 上课讲到的设计模式总结
  2. 使用@Async异步注解导致该Bean在循环依赖时启动报BeanCurrentlyInCreationException异常的根本原因分析,以及提供解决方案
  3. 网站漏洞检测针对区块链网站安全分析
  4. 图解带你掌握`JVM`运行时核心内存区
  5. Stata和Matlab联合处理金融数据
  6. vs2012 怎样解决 未能正确加载“Microsoft.VisualStudio.Editor.Implementation.EditorPackage”包的问题
  7. 简书红米MIUI-7.5兼容性缺陷:长按文字时弹出的复制粘贴菜单缺少背景色
  8. mysql php 空格函数_MySQL_mysql 强大的trim() 函数,mysql中的去除左空格函数: LTRI - phpStudy...
  9. SpringMVC和Structs2
  10. Java 导出Excel 自定义模板
  11. 自适应PID控制基本概念及常用自适应算法
  12. linux限制syslog大小,c – 如何限制syslog管理的日志文件的总大小?
  13. 游戏编程精粹1---数学技巧---可预测随机数---2
  14. 小米扫地机器人原地不动_扫地机器人在原地打转是什么原因?小编来告诉你!...
  15. Excel 删除数据temp 恢复
  16. 12.19 - 每日一题 - 408
  17. 【Python工具】Python实现一款支持各大平台的视频下载器 | 附源码
  18. 机顶盒联机调试的方法
  19. SpringBoot 显示Swagger Api 文档
  20. 商人的诀窍 结构体

热门文章

  1. python -yield理解
  2. 给web请求加遮罩动画
  3. Mysql5.7安装错误处理与主从同步及!
  4. centos ntfs-3g 安装和使用
  5. 大型网站技术架构:核心原理与案例分析阅读笔记二
  6. 自己写getElementsByClass()方法
  7. HDU 4445 Crazy Tank --枚举
  8. 数据库入门浅析:ASP.NET与MySQL连接
  9. x86标志位符号表示(PF奇偶位)
  10. 使用opencv实现实例分割,一学就会|附源码