[
  {
    "path": "Acceptor.cc",
    "content": "#include <sys/types.h>\n#include <sys/socket.h>\n#include <errno.h>\n#include <unistd.h>\n\n#include \"Acceptor.h\"\n#include \"Logger.h\"\n#include \"InetAddress.h\"\n\nstatic int createNonblocking()\n{\n    int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);\n    if (sockfd < 0)\n    {\n        LOG_FATAL(\"%s:%s:%d listen socket create err:%d\\n\", __FILE__, __FUNCTION__, __LINE__, errno);\n    }\n    return sockfd;\n}\n\nAcceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport)\n    : loop_(loop)\n    , acceptSocket_(createNonblocking())\n    , acceptChannel_(loop, acceptSocket_.fd())\n    , listenning_(false)\n{\n    acceptSocket_.setReuseAddr(true);\n    acceptSocket_.setReusePort(true);\n    acceptSocket_.bindAddress(listenAddr);\n    // TcpServer::start() => Acceptor.listen() 如果有新用户连接 要执行一个回调(accept => connfd => 打包成Channel => 唤醒subloop)\n    // baseloop监听到有事件发生 => acceptChannel_(listenfd) => 执行该回调函数\n    acceptChannel_.setReadCallback(\n        std::bind(&Acceptor::handleRead, this));\n}\n\nAcceptor::~Acceptor()\n{\n    acceptChannel_.disableAll();    // 把从Poller中感兴趣的事件删除掉\n    acceptChannel_.remove();        // 调用EventLoop->removeChannel => Poller->removeChannel 把Poller的ChannelMap对应的部分删除\n}\n\nvoid Acceptor::listen()\n{\n    listenning_ = true;\n    acceptSocket_.listen();         // listen\n    acceptChannel_.enableReading(); // acceptChannel_注册至Poller !重要\n}\n\n// listenfd有事件发生了，就是有新用户连接了\nvoid Acceptor::handleRead()\n{\n    InetAddress peerAddr;\n    int connfd = acceptSocket_.accept(&peerAddr);\n    if (connfd >= 0)\n    {\n        if (NewConnectionCallback_)\n        {\n            NewConnectionCallback_(connfd, peerAddr); // 轮询找到subLoop 唤醒并分发当前的新客户端的Channel\n        }\n        else\n        {\n            ::close(connfd);\n        }\n    }\n    else\n    {\n        LOG_ERROR(\"%s:%s:%d accept err:%d\\n\", __FILE__, __FUNCTION__, __LINE__, errno);\n        if (errno == EMFILE)\n        {\n            LOG_ERROR(\"%s:%s:%d sockfd reached limit\\n\", __FILE__, __FUNCTION__, __LINE__);\n        }\n    }\n}"
  },
  {
    "path": "Acceptor.h",
    "content": "#pragma once\n\n#include <functional>\n\n#include \"noncopyable.h\"\n#include \"Socket.h\"\n#include \"Channel.h\"\n\nclass EventLoop;\nclass InetAddress;\n\nclass Acceptor : noncopyable\n{\npublic:\n    using NewConnectionCallback = std::function<void(int sockfd, const InetAddress &)>;\n\n    Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport);\n    ~Acceptor();\n\n    void setNewConnectionCallback(const NewConnectionCallback &cb) { NewConnectionCallback_ = cb; }\n\n    bool listenning() const { return listenning_; }\n    void listen();\n\nprivate:\n    void handleRead();\n\n    EventLoop *loop_; // Acceptor用的就是用户定义的那个baseLoop 也称作mainLoop\n    Socket acceptSocket_;\n    Channel acceptChannel_;\n    NewConnectionCallback NewConnectionCallback_;\n    bool listenning_;\n};"
  },
  {
    "path": "Buffer.cc",
    "content": "#include <errno.h>\n#include <sys/uio.h>\n#include <unistd.h>\n\n#include \"Buffer.h\"\n\n/**\n * 从fd上读取数据 Poller工作在LT模式\n * Buffer缓冲区是有大小的！ 但是从fd上读取数据的时候 却不知道tcp数据的最终大小\n *\n * @description: 从socket读到缓冲区的方法是使用readv先读至buffer_，\n * Buffer_空间如果不够会读入到栈上65536个字节大小的空间，然后以append的\n * 方式追加入buffer_。既考虑了避免系统调用带来开销，又不影响数据的接收。\n **/\nssize_t Buffer::readFd(int fd, int *saveErrno)\n{\n    // 栈额外空间，用于从套接字往出读时，当buffer_暂时不够用时暂存数据，待buffer_重新分配足够空间后，在把数据交换给buffer_。\n    char extrabuf[65536] = {0}; // 栈上内存空间 65536/1024 = 64KB\n\n    /*\n    struct iovec {\n        ptr_t iov_base; // iov_base指向的缓冲区存放的是readv所接收的数据或是writev将要发送的数据\n        size_t iov_len; // iov_len在各种情况下分别确定了接收的最大长度以及实际写入的长度\n    };\n    */\n\n    // 使用iovec分配两个连续的缓冲区\n    struct iovec vec[2];\n    const size_t writable = writableBytes(); // 这是Buffer底层缓冲区剩余的可写空间大小 不一定能完全存储从fd读出的数据\n\n    // 第一块缓冲区，指向可写空间\n    vec[0].iov_base = begin() + writerIndex_;\n    vec[0].iov_len = writable;\n    // 第二块缓冲区，指向栈空间\n    vec[1].iov_base = extrabuf;\n    vec[1].iov_len = sizeof(extrabuf);\n\n    // when there is enough space in this buffer, don't read into extrabuf.\n    // when extrabuf is used, we read 128k-1 bytes at most.\n    // 这里之所以说最多128k-1字节，是因为若writable为64k-1，那么需要两个缓冲区 第一个64k-1 第二个64k 所以做多128k-1\n    // 如果第一个缓冲区>=64k 那就只采用一个缓冲区 而不使用栈空间extrabuf[65536]的内容\n    const int iovcnt = (writable < sizeof(extrabuf)) ? 2 : 1;\n    const ssize_t n = ::readv(fd, vec, iovcnt);\n\n    if (n < 0)\n    {\n        *saveErrno = errno;\n    }\n    else if (n <= writable) // Buffer的可写缓冲区已经够存储读出来的数据了\n    {\n        writerIndex_ += n;\n    }\n    else // extrabuf里面也写入了n-writable长度的数据\n    {\n        writerIndex_ = buffer_.size();\n        append(extrabuf, n - writable); // 对buffer_扩容 并将extrabuf存储的另一部分数据追加至buffer_\n    }\n    return n;\n}\n\n// inputBuffer_.readFd表示将对端数据读到inputBuffer_中，移动writerIndex_指针\n// outputBuffer_.writeFd标示将数据写入到outputBuffer_中，从readerIndex_开始，可以写readableBytes()个字节\nssize_t Buffer::writeFd(int fd, int *saveErrno)\n{\n    ssize_t n = ::write(fd, peek(), readableBytes());\n    if (n < 0)\n    {\n        *saveErrno = errno;\n    }\n    return n;\n}"
  },
  {
    "path": "Buffer.h",
    "content": "#pragma once\n\n#include <vector>\n#include <string>\n#include <algorithm>\n#include <stddef.h>\n\n// 网络库底层的缓冲区类型定义\nclass Buffer\n{\npublic:\n    static const size_t kCheapPrepend = 8;\n    static const size_t kInitialSize = 1024;\n\n    explicit Buffer(size_t initalSize = kInitialSize)\n        : buffer_(kCheapPrepend + initalSize)\n        , readerIndex_(kCheapPrepend)\n        , writerIndex_(kCheapPrepend)\n    {\n    }\n\n    size_t readableBytes() const { return writerIndex_ - readerIndex_; }\n    size_t writableBytes() const { return buffer_.size() - writerIndex_; }\n    size_t prependableBytes() const { return readerIndex_; }\n\n    // 返回缓冲区中可读数据的起始地址\n    const char *peek() const { return begin() + readerIndex_; }\n    void retrieve(size_t len)\n    {\n        if (len < readableBytes())\n        {\n            readerIndex_ += len; // 说明应用只读取了可读缓冲区数据的一部分，就是len长度 还剩下readerIndex+=len到writerIndex_的数据未读\n        }\n        else // len == readableBytes()\n        {\n            retrieveAll();\n        }\n    }\n    void retrieveAll()\n    {\n        readerIndex_ = kCheapPrepend;\n        writerIndex_ = kCheapPrepend;\n    }\n\n    // 把onMessage函数上报的Buffer数据 转成string类型的数据返回\n    std::string retrieveAllAsString() { return retrieveAsString(readableBytes()); }\n    std::string retrieveAsString(size_t len)\n    {\n        std::string result(peek(), len);\n        retrieve(len); // 上面一句把缓冲区中可读的数据已经读取出来 这里肯定要对缓冲区进行复位操作\n        return result;\n    }\n\n    // buffer_.size - writerIndex_\n    void ensureWritableBytes(size_t len)\n    {\n        if (writableBytes() < len)\n        {\n            makeSpace(len); // 扩容\n        }\n    }\n\n    // 把[data, data+len]内存上的数据添加到writable缓冲区当中\n    void append(const char *data, size_t len)\n    {\n        ensureWritableBytes(len);\n        std::copy(data, data+len, beginWrite());\n        writerIndex_ += len;\n    }\n    char *beginWrite() { return begin() + writerIndex_; }\n    const char *beginWrite() const { return begin() + writerIndex_; }\n\n    // 从fd上读取数据\n    ssize_t readFd(int fd, int *saveErrno);\n    // 通过fd发送数据\n    ssize_t writeFd(int fd, int *saveErrno);\n\nprivate:\n    // vector底层数组首元素的地址 也就是数组的起始地址\n    char *begin() { return &*buffer_.begin(); }\n    const char *begin() const { return &*buffer_.begin(); }\n\n    void makeSpace(size_t len)\n    {\n        /**\n         * | kCheapPrepend |xxx| reader | writer |                     // xxx标示reader中已读的部分\n         * | kCheapPrepend | reader ｜          len          |\n         **/\n        if (writableBytes() + prependableBytes() < len + kCheapPrepend) // 也就是说 len > xxx + writer的部分\n        {\n            buffer_.resize(writerIndex_ + len);\n        }\n        else // 这里说明 len <= xxx + writer 把reader搬到从xxx开始 使得xxx后面是一段连续空间\n        {\n            size_t readable = readableBytes(); // readable = reader的长度\n            std::copy(begin() + readerIndex_,\n                      begin() + writerIndex_,  // 把这一部分数据拷贝到begin+kCheapPrepend起始处\n                      begin() + kCheapPrepend);\n            readerIndex_ = kCheapPrepend;\n            writerIndex_ = readerIndex_ + readable;\n        }\n    }\n\n    std::vector<char> buffer_;\n    size_t readerIndex_;\n    size_t writerIndex_;\n};\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.5)\nproject(mymuduo)\n\n# mymuduo最终编译成so动态库 设置动态库的路径 放置项目根目录的lib文件夹下面\nset(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)\n\n# 设置调试信息  以及启动C++11语言标准\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -g -std=c++11\")\n\n# 定义参与编译的源代码文件\naux_source_directory(. SRC_LIST)\n\n# 编译动态库\nadd_library(mymuduo SHARED ${SRC_LIST})"
  },
  {
    "path": "Callbacks.h",
    "content": "#pragma once\n\n#include <memory>\n#include <functional>\n\nclass Buffer;\nclass TcpConnection;\nclass Timestamp;\n\nusing TcpConnectionPtr = std::shared_ptr<TcpConnection>;\nusing ConnectionCallback = std::function<void(const TcpConnectionPtr &)>;\nusing CloseCallback = std::function<void(const TcpConnectionPtr &)>;\nusing WriteCompleteCallback = std::function<void(const TcpConnectionPtr &)>;\nusing HighWaterMarkCallback = std::function<void(const TcpConnectionPtr &, size_t)>;\n\nusing MessageCallback = std::function<void(const TcpConnectionPtr &,\n                                           Buffer *,\n                                           Timestamp)>;"
  },
  {
    "path": "Channel.cc",
    "content": "#include <sys/epoll.h>\n\n#include \"Channel.h\"\n#include \"EventLoop.h\"\n#include \"Logger.h\"\n\nconst int Channel::kNoneEvent = 0;\nconst int Channel::kReadEvent = EPOLLIN | EPOLLPRI;\nconst int Channel::kWriteEvent = EPOLLOUT;\n\n// EventLoop: ChannelList Poller\nChannel::Channel(EventLoop *loop, int fd)\n    : loop_(loop)\n    , fd_(fd)\n    , events_(0)\n    , revents_(0)\n    , index_(-1)\n    , tied_(false)\n{\n}\n\nChannel::~Channel()\n{\n}\n\n// channel的tie方法什么时候调用过?  TcpConnection => channel\n/**\n * TcpConnection中注册了Chnanel对应的回调函数，传入的回调函数均为TcpConnection\n * 对象的成员方法，因此可以说明一点就是：Channel的结束一定早于TcpConnection对象！\n * 此处用tie去解决TcoConnection和Channel的生命周期时长问题，从而保证了Channel对\n * 象能够在TcpConnection销毁前销毁。\n **/\nvoid Channel::tie(const std::shared_ptr<void> &obj)\n{\n    tie_ = obj;\n    tied_ = true;\n}\n\n/**\n * 当改变channel所表示的fd的events事件后，update负责再poller里面更改fd相应的事件epoll_ctl\n **/\nvoid Channel::update()\n{\n    // 通过channel所属的eventloop，调用poller的相应方法，注册fd的events事件\n    loop_->updateChannel(this);\n}\n\n// 在channel所属的EventLoop中把当前的channel删除掉\nvoid Channel::remove()\n{\n    loop_->removeChannel(this);\n}\n\nvoid Channel::handleEvent(Timestamp receiveTime)\n{\n    if (tied_)\n    {\n        std::shared_ptr<void> guard = tie_.lock();\n        if (guard)\n        {\n            handleEventWithGuard(receiveTime);\n        }\n        // 如果提升失败了 就不做任何处理 说明Channel的TcpConnection对象已经不存在了\n    }\n    else\n    {\n        handleEventWithGuard(receiveTime);\n    }\n}\n\nvoid Channel::handleEventWithGuard(Timestamp receiveTime)\n{\n    LOG_INFO(\"channel handleEvent revents:%d\\n\", revents_);\n    // 关闭\n    if ((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)) // 当TcpConnection对应Channel 通过shutdown 关闭写端 epoll触发EPOLLHUP\n    {\n        if (closeCallback_)\n        {\n            closeCallback_();\n        }\n    }\n    // 错误\n    if (revents_ & EPOLLERR)\n    {\n        if (errorCallback_)\n        {\n            errorCallback_();\n        }\n    }\n    // 读\n    if (revents_ & (EPOLLIN | EPOLLPRI))\n    {\n        if (readCallback_)\n        {\n            readCallback_(receiveTime);\n        }\n    }\n    // 写\n    if (revents_ & EPOLLOUT)\n    {\n        if (writeCallback_)\n        {\n            writeCallback_();\n        }\n    }\n}"
  },
  {
    "path": "Channel.h",
    "content": "#pragma once\n\n#include <functional>\n#include <memory>\n\n#include \"noncopyable.h\"\n#include \"Timestamp.h\"\n\nclass EventLoop;\n\n/**\n * 理清楚 EventLoop、Channel、Poller之间的关系  Reactor模型上对应多路事件分发器\n * Channel理解为通道 封装了sockfd和其感兴趣的event 如EPOLLIN、EPOLLOUT事件 还绑定了poller返回的具体事件\n **/\nclass Channel : noncopyable\n{\npublic:\n    using EventCallback = std::function<void()>; // muduo仍使用typedef\n    using ReadEventCallback = std::function<void(Timestamp)>;\n\n    Channel(EventLoop *loop, int fd);\n    ~Channel();\n\n    // fd得到Poller通知以后 处理事件 handleEvent在EventLoop::loop()中调用\n    void handleEvent(Timestamp receiveTime);\n\n    // 设置回调函数对象\n    void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }\n    void setWriteCallback(EventCallback cb) { writeCallback_ = std::move(cb); }\n    void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }\n    void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }\n\n    // 防止当channel被手动remove掉 channel还在执行回调操作\n    void tie(const std::shared_ptr<void> &);\n\n    int fd() const { return fd_; }\n    int events() const { return events_; }\n    void set_revents(int revt) { revents_ = revt; }\n\n    // 设置fd相应的事件状态 相当于epoll_ctl add delete\n    void enableReading() { events_ |= kReadEvent; update(); }\n    void disableReading() { events_ &= ~kReadEvent; update(); }\n    void enableWriting() { events_ |= kWriteEvent; update(); }\n    void disableWriting() { events_ &= ~kWriteEvent; update(); }\n    void disableAll() { events_ = kNoneEvent; update(); }\n\n    // 返回fd当前的事件状态\n    bool isNoneEvent() const { return events_ == kNoneEvent; }\n    bool isWriting() const { return events_ & kWriteEvent; }\n    bool isReading() const { return events_ & kReadEvent; }\n\n    int index() { return index_; }\n    void set_index(int idx) { index_ = idx; }\n\n    // one loop per thread\n    EventLoop *ownerLoop() { return loop_; }\n    void remove();\nprivate:\n\n    void update();\n    void handleEventWithGuard(Timestamp receiveTime);\n\n    static const int kNoneEvent;\n    static const int kReadEvent;\n    static const int kWriteEvent;\n\n    EventLoop *loop_; // 事件循环\n    const int fd_;    // fd，Poller监听的对象\n    int events_;      // 注册fd感兴趣的事件\n    int revents_;     // Poller返回的具体发生的事件\n    int index_;\n\n    std::weak_ptr<void> tie_;\n    bool tied_;\n\n    // 因为channel通道里可获知fd最终发生的具体的事件events，所以它负责调用具体事件的回调操作\n    ReadEventCallback readCallback_;\n    EventCallback writeCallback_;\n    EventCallback closeCallback_;\n    EventCallback errorCallback_;\n};"
  },
  {
    "path": "CurrentThread.cc",
    "content": "#include \"CurrentThread.h\"\n\nnamespace CurrentThread\n{\n    __thread int t_cachedTid = 0;\n\n    void cacheTid()\n    {\n        if (t_cachedTid == 0)\n        {\n            t_cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));\n        }\n    }\n}"
  },
  {
    "path": "CurrentThread.h",
    "content": "#pragma once\n\n#include <unistd.h>\n#include <sys/syscall.h>\n\nnamespace CurrentThread\n{\n    extern __thread int t_cachedTid; // 保存tid缓存 因为系统调用非常耗时 拿到tid后将其保存\n\n    void cacheTid();\n\n    inline int tid() // 内联函数只在当前文件中起作用\n    {\n        if (__builtin_expect(t_cachedTid == 0, 0)) // __builtin_expect 是一种底层优化 此语句意思是如果还未获取tid 进入if 通过cacheTid()系统调用获取tid\n        {\n            cacheTid();\n        }\n        return t_cachedTid;\n    }\n}"
  },
  {
    "path": "DefaultPoller.cc",
    "content": "#include <stdlib.h>\n\n#include \"Poller.h\"\n#include \"EPollPoller.h\"\n\nPoller *Poller::newDefaultPoller(EventLoop *loop)\n{\n    if (::getenv(\"MUDUO_USE_POLL\"))\n    {\n        return nullptr; // 生成poll的实例\n    }\n    else\n    {\n        return new EPollPoller(loop); // 生成epoll的实例\n    }\n}"
  },
  {
    "path": "EPollPoller.cc",
    "content": "#include <errno.h>\n#include <unistd.h>\n#include <string.h>\n\n#include \"EPollPoller.h\"\n#include \"Logger.h\"\n#include \"Channel.h\"\n\nconst int kNew = -1;    // 某个channel还没添加至Poller          // channel的成员index_初始化为-1\nconst int kAdded = 1;   // 某个channel已经添加至Poller\nconst int kDeleted = 2; // 某个channel已经从Poller删除\n\nEPollPoller::EPollPoller(EventLoop *loop)\n    : Poller(loop)\n    , epollfd_(::epoll_create1(EPOLL_CLOEXEC))\n    , events_(kInitEventListSize) // vector<epoll_event>(16)\n{\n    if (epollfd_ < 0)\n    {\n        LOG_FATAL(\"epoll_create error:%d \\n\", errno);\n    }\n}\n\nEPollPoller::~EPollPoller()\n{\n    ::close(epollfd_);\n}\n\nTimestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels)\n{\n    // 由于频繁调用poll 实际上应该用LOG_DEBUG输出日志更为合理 当遇到并发场景 关闭DEBUG日志提升效率\n    LOG_INFO(\"func=%s => fd total count:%lu\\n\", __FUNCTION__, channels_.size());\n\n    int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs);\n    int saveErrno = errno;\n    Timestamp now(Timestamp::now());\n\n    if (numEvents > 0)\n    {\n        LOG_INFO(\"%d events happend\\n\", numEvents); // LOG_DEBUG最合理\n        fillActiveChannels(numEvents, activeChannels);\n        if (numEvents == events_.size()) // 扩容操作\n        {\n            events_.resize(events_.size() * 2);\n        }\n    }\n    else if (numEvents == 0)\n    {\n        LOG_DEBUG(\"%s timeout!\\n\", __FUNCTION__);\n    }\n    else\n    {\n        if (saveErrno != EINTR)\n        {\n            errno = saveErrno;\n            LOG_ERROR(\"EPollPoller::poll() error!\");\n        }\n    }\n    return now;\n}\n\n// channel update remove => EventLoop updateChannel removeChannel => Poller updateChannel removeChannel\nvoid EPollPoller::updateChannel(Channel *channel)\n{\n    const int index = channel->index();\n    LOG_INFO(\"func=%s => fd=%d events=%d index=%d\\n\", __FUNCTION__, channel->fd(), channel->events(), index);\n\n    if (index == kNew || index == kDeleted)\n    {\n        if (index == kNew)\n        {\n            int fd = channel->fd();\n            channels_[fd] = channel;\n        }\n        else // index == kAdd\n        {\n        }\n        channel->set_index(kAdded);\n        update(EPOLL_CTL_ADD, channel);\n    }\n    else // channel已经在Poller中注册过了\n    {\n        int fd = channel->fd();\n        if (channel->isNoneEvent())\n        {\n            update(EPOLL_CTL_DEL, channel);\n            channel->set_index(kDeleted);\n        }\n        else\n        {\n            update(EPOLL_CTL_MOD, channel);\n        }\n    }\n}\n\n// 从Poller中删除channel\nvoid EPollPoller::removeChannel(Channel *channel)\n{\n    int fd = channel->fd();\n    channels_.erase(fd);\n\n    LOG_INFO(\"func=%s => fd=%d\\n\", __FUNCTION__, fd);\n\n    int index = channel->index();\n    if (index == kAdded)\n    {\n        update(EPOLL_CTL_DEL, channel);\n    }\n    channel->set_index(kNew);\n}\n\n// 填写活跃的连接\nvoid EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const\n{\n    for (int i = 0; i < numEvents; ++i)\n    {\n        Channel *channel = static_cast<Channel *>(events_[i].data.ptr);\n        channel->set_revents(events_[i].events);\n        activeChannels->push_back(channel); // EventLoop就拿到了它的Poller给它返回的所有发生事件的channel列表了\n    }\n}\n\n// 更新channel通道 其实就是调用epoll_ctl add/mod/del\nvoid EPollPoller::update(int operation, Channel *channel)\n{\n    epoll_event event;\n    ::memset(&event, 0, sizeof(event));\n\n    int fd = channel->fd();\n\n    event.events = channel->events();\n    event.data.fd = fd;\n    event.data.ptr = channel;\n\n    if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)\n    {\n        if (operation == EPOLL_CTL_DEL)\n        {\n            LOG_ERROR(\"epoll_ctl del error:%d\\n\", errno);\n        }\n        else\n        {\n            LOG_FATAL(\"epoll_ctl add/mod error:%d\\n\", errno);\n        }\n    }\n}"
  },
  {
    "path": "EPollPoller.h",
    "content": "#pragma once\n\n#include <vector>\n#include <sys/epoll.h>\n\n#include \"Poller.h\"\n#include \"Timestamp.h\"\n\n/**\n * epoll的使用:\n * 1. epoll_create\n * 2. epoll_ctl (add, mod, del)\n * 3. epoll_wait\n **/\n\nclass Channel;\n\nclass EPollPoller : public Poller\n{\npublic:\n    EPollPoller(EventLoop *loop);\n    ~EPollPoller() override;\n\n    // 重写基类Poller的抽象方法\n    Timestamp poll(int timeoutMs, ChannelList *activeChannels) override;\n    void updateChannel(Channel *channel) override;\n    void removeChannel(Channel *channel) override;\n\nprivate:\n    static const int kInitEventListSize = 16;\n\n    // 填写活跃的连接\n    void fillActiveChannels(int numEvents, ChannelList *activeChannels) const;\n    // 更新channel通道 其实就是调用epoll_ctl\n    void update(int operation, Channel *channel);\n\n    using EventList = std::vector<epoll_event>; // C++中可以省略struct 直接写epoll_event即可\n\n    int epollfd_;      // epoll_create创建返回的fd保存在epollfd_中\n    EventList events_; // 用于存放epoll_wait返回的所有发生的事件的文件描述符事件集\n};"
  },
  {
    "path": "EventLoop.cc",
    "content": "#include <sys/eventfd.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <memory>\n\n#include \"EventLoop.h\"\n#include \"Logger.h\"\n#include \"Channel.h\"\n#include \"Poller.h\"\n\n// 防止一个线程创建多个EventLoop\n__thread EventLoop *t_loopInThisThread = nullptr;\n\n// 定义默认的Poller IO复用接口的超时时间\nconst int kPollTimeMs = 10000; // 10000毫秒 = 10秒钟\n\n/* 创建线程之后主线程和子线程谁先运行是不确定的。\n * 通过一个eventfd在线程之间传递数据的好处是多个线程无需上锁就可以实现同步。\n * eventfd支持的最低内核版本为Linux 2.6.27,在2.6.26及之前的版本也可以使用eventfd，但是flags必须设置为0。\n * 函数原型：\n *     #include <sys/eventfd.h>\n *     int eventfd(unsigned int initval, int flags);\n * 参数说明：\n *      initval,初始化计数器的值。\n *      flags, EFD_NONBLOCK,设置socket为非阻塞。\n *             EFD_CLOEXEC，执行fork的时候，在父进程中的描述符会自动关闭，子进程中的描述符保留。\n * 场景：\n *     eventfd可以用于同一个进程之中的线程之间的通信。\n *     eventfd还可以用于同亲缘关系的进程之间的通信。\n *     eventfd用于不同亲缘关系的进程之间通信的话需要把eventfd放在几个进程共享的共享内存中（没有测试过）。\n */\n// 创建wakeupfd 用来notify唤醒subReactor处理新来的channel\nint createEventfd()\n{\n    int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);\n    if (evtfd < 0)\n    {\n        LOG_FATAL(\"eventfd error:%d\\n\", errno);\n    }\n    return evtfd;\n}\n\nEventLoop::EventLoop()\n    : looping_(false)\n    , quit_(false)\n    , callingPendingFunctors_(false)\n    , threadId_(CurrentThread::tid())\n    , poller_(Poller::newDefaultPoller(this))\n    , wakeupFd_(createEventfd())\n    , wakeupChannel_(new Channel(this, wakeupFd_))\n{\n    LOG_DEBUG(\"EventLoop created %p in thread %d\\n\", this, threadId_);\n    if (t_loopInThisThread)\n    {\n        LOG_FATAL(\"Another EventLoop %p exists in this thread %d\\n\", t_loopInThisThread, threadId_);\n    }\n    else\n    {\n        t_loopInThisThread = this;\n    }\n    \n    wakeupChannel_->setReadCallback(\n        std::bind(&EventLoop::handleRead, this)); // 设置wakeupfd的事件类型以及发生事件后的回调操作\n    \n    wakeupChannel_->enableReading(); // 每一个EventLoop都将监听wakeupChannel_的EPOLL读事件了\n}\nEventLoop::~EventLoop()\n{\n    wakeupChannel_->disableAll(); // 给Channel移除所有感兴趣的事件\n    wakeupChannel_->remove();     // 把Channel从EventLoop上删除掉\n    ::close(wakeupFd_);\n    t_loopInThisThread = nullptr;\n}\n\n// 开启事件循环\nvoid EventLoop::loop()\n{\n    looping_ = true;\n    quit_ = false;\n\n    LOG_INFO(\"EventLoop %p start looping\\n\", this);\n\n    while (!quit_)\n    {\n        activeChannels_.clear();\n        pollRetureTime_ = poller_->poll(kPollTimeMs, &activeChannels_);\n        for (Channel *channel : activeChannels_)\n        {\n            // Poller监听哪些channel发生了事件 然后上报给EventLoop 通知channel处理相应的事件\n            channel->handleEvent(pollRetureTime_);\n        }\n        /**\n         * 执行当前EventLoop事件循环需要处理的回调操作 对于线程数 >=2 的情况 IO线程 mainloop(mainReactor) 主要工作：\n         * accept接收连接 => 将accept返回的connfd打包为Channel => TcpServer::newConnection通过轮询将TcpConnection对象分配给subloop处理\n         *\n         * mainloop调用queueInLoop将回调加入subloop（该回调需要subloop执行 但subloop还在poller_->poll处阻塞） queueInLoop通过wakeup将subloop唤醒\n         **/\n        doPendingFunctors();\n    }\n    LOG_INFO(\"EventLoop %p stop looping.\\n\", this);\n    looping_ = false;\n}\n\n/**\n * 退出事件循环\n * 1. 如果loop在自己的线程中调用quit成功了 说明当前线程已经执行完毕了loop()函数的poller_->poll并退出\n * 2. 如果不是当前EventLoop所属线程中调用quit退出EventLoop 需要唤醒EventLoop所属线程的epoll_wait\n *\n * 比如在一个subloop(worker)中调用mainloop(IO)的quit时 需要唤醒mainloop(IO)的poller_->poll 让其执行完loop()函数\n *\n * ！！！ 注意： 正常情况下 mainloop负责请求连接 将回调写入subloop中 通过生产者消费者模型即可实现线程安全的队列\n * ！！！       但是muduo通过wakeup()机制 使用eventfd创建的wakeupFd_ notify 使得mainloop和subloop之间能够进行通信\n **/\nvoid EventLoop::quit()\n{\n    quit_ = true;\n\n    if (!isInLoopThread())\n    {\n        wakeup();\n    }\n}\n\n// 在当前loop中执行cb\nvoid EventLoop::runInLoop(Functor cb)\n{\n    if (isInLoopThread()) // 当前EventLoop中执行回调\n    {\n        cb();\n    }\n    else // 在非当前EventLoop线程中执行cb，就需要唤醒EventLoop所在线程执行cb\n    {\n        queueInLoop(cb);\n    }\n}\n\n// 把cb放入队列中 唤醒loop所在的线程执行cb\nvoid EventLoop::queueInLoop(Functor cb)\n{\n    {\n        std::unique_lock<std::mutex> lock(mutex_);\n        pendingFunctors_.emplace_back(cb);\n    }\n\n    /**\n     * || callingPendingFunctors的意思是 当前loop正在执行回调中 但是loop的pendingFunctors_中又加入了新的回调 需要通过wakeup写事件\n     * 唤醒相应的需要执行上面回调操作的loop的线程 让loop()下一次poller_->poll()不再阻塞（阻塞的话会延迟前一次新加入的回调的执行），然后\n     * 继续执行pendingFunctors_中的回调函数\n     **/\n    if (!isInLoopThread() || callingPendingFunctors_)\n    {\n        wakeup(); // 唤醒loop所在线程\n    }\n}\n\nvoid EventLoop::handleRead()\n{\n    uint64_t one = 1;\n    ssize_t n = read(wakeupFd_, &one, sizeof(one));\n    if (n != sizeof(one))\n    {\n        LOG_ERROR(\"EventLoop::handleRead() reads %lu bytes instead of 8\\n\", n);\n    }\n}\n\n// 用来唤醒loop所在线程 向wakeupFd_写一个数据 wakeupChannel就发生读事件 当前loop线程就会被唤醒\nvoid EventLoop::wakeup()\n{\n    uint64_t one = 1;\n    ssize_t n = write(wakeupFd_, &one, sizeof(one));\n    if (n != sizeof(one))\n    {\n        LOG_ERROR(\"EventLoop::wakeup() writes %lu bytes instead of 8\\n\", n);\n    }\n}\n\n// EventLoop的方法 => Poller的方法\nvoid EventLoop::updateChannel(Channel *channel)\n{\n    poller_->updateChannel(channel);\n}\n\nvoid EventLoop::removeChannel(Channel *channel)\n{\n    poller_->removeChannel(channel);\n}\n\nbool EventLoop::hasChannel(Channel *channel)\n{\n    return poller_->hasChannel(channel);\n}\n\nvoid EventLoop::doPendingFunctors()\n{\n    std::vector<Functor> functors;\n    callingPendingFunctors_ = true;\n\n    {\n        std::unique_lock<std::mutex> lock(mutex_);\n        functors.swap(pendingFunctors_); // 交换的方式减少了锁的临界区范围 提升效率 同时避免了死锁 如果执行functor()在临界区内 且functor()中调用queueInLoop()就会产生死锁\n    }\n\n    for (const Functor &functor : functors)\n    {\n        functor(); // 执行当前loop需要执行的回调操作\n    }\n\n    callingPendingFunctors_ = false;\n}\n"
  },
  {
    "path": "EventLoop.h",
    "content": "#pragma once\n\n#include <functional>\n#include <vector>\n#include <atomic>\n#include <memory>\n#include <mutex>\n\n#include \"noncopyable.h\"\n#include \"Timestamp.h\"\n#include \"CurrentThread.h\"\n\nclass Channel;\nclass Poller;\n\n// 事件循环类 主要包含了两个大模块 Channel Poller(epoll的抽象)\nclass EventLoop : noncopyable\n{\npublic:\n    using Functor = std::function<void()>;\n\n    EventLoop();\n    ~EventLoop();\n\n    // 开启事件循环\n    void loop();\n    // 退出事件循环\n    void quit();\n\n    Timestamp pollReturnTime() const { pollRetureTime_; }\n\n    // 在当前loop中执行\n    void runInLoop(Functor cb);\n    // 把上层注册的回调函数cb放入队列中 唤醒loop所在的线程执行cb\n    void queueInLoop(Functor cb);\n\n    // 通过eventfd唤醒loop所在的线程\n    void wakeup();\n\n    // EventLoop的方法 => Poller的方法\n    void updateChannel(Channel *channel);\n    void removeChannel(Channel *channel);\n    bool hasChannel(Channel *channel);\n\n    // 判断EventLoop对象是否在自己的线程里\n    bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } // threadId_为EventLoop创建时的线程id CurrentThread::tid()为当前线程id\n\nprivate:\n    void handleRead();        // 给eventfd返回的文件描述符wakeupFd_绑定的事件回调 当wakeup()时 即有事件发生时 调用handleRead()读wakeupFd_的8字节 同时唤醒阻塞的epoll_wait\n    void doPendingFunctors(); // 执行上层回调\n\n    using ChannelList = std::vector<Channel *>;\n\n    std::atomic_bool looping_; // 原子操作 底层通过CAS实现\n    std::atomic_bool quit_;    // 标识退出loop循环\n\n    const pid_t threadId_; // 记录当前EventLoop是被哪个线程id创建的 即标识了当前EventLoop的所属线程id\n\n    Timestamp pollRetureTime_; // Poller返回发生事件的Channels的时间点\n    std::unique_ptr<Poller> poller_;\n\n    int wakeupFd_; // 作用：当mainLoop获取一个新用户的Channel 需通过轮询算法选择一个subLoop 通过该成员唤醒subLoop处理Channel\n    std::unique_ptr<Channel> wakeupChannel_;\n\n    ChannelList activeChannels_; // 返回Poller检测到当前有事件发生的所有Channel列表\n\n    std::atomic_bool callingPendingFunctors_; // 标识当前loop是否有需要执行的回调操作\n    std::vector<Functor> pendingFunctors_;    // 存储loop需要执行的所有回调操作\n    std::mutex mutex_;                        // 互斥锁 用来保护上面vector容器的线程安全操作\n};"
  },
  {
    "path": "EventLoopThread.cc",
    "content": "#include \"EventLoopThread.h\"\n#include \"EventLoop.h\"\n\nEventLoopThread::EventLoopThread(const ThreadInitCallback &cb,\n                                 const std::string &name)\n    : loop_(nullptr)\n    , exiting_(false)\n    , thread_(std::bind(&EventLoopThread::threadFunc, this), name)\n    , mutex_()\n    , cond_()\n    , callback_(cb)\n{\n}\n\nEventLoopThread::~EventLoopThread()\n{\n    exiting_ = true;\n    if (loop_ != nullptr)\n    {\n        loop_->quit();\n        thread_.join();\n    }\n}\n\nEventLoop *EventLoopThread::startLoop()\n{\n    thread_.start(); // 启用底层线程Thread类对象thread_中通过start()创建的线程\n\n    EventLoop *loop = nullptr;\n    {\n        std::unique_lock<std::mutex> lock(mutex_);\n        while(loop_ == nullptr)\n        {\n            cond_.wait(lock);\n        }\n        loop = loop_;\n    }\n    return loop;\n}\n\n// 下面这个方法 是在单独的新线程里运行的\nvoid EventLoopThread::threadFunc()\n{\n    EventLoop loop; // 创建一个独立的EventLoop对象 和上面的线程是一一对应的 级one loop per thread\n\n    if (callback_)\n    {\n        callback_(&loop);\n    }\n\n    {\n        std::unique_lock<std::mutex> lock(mutex_);\n        loop_ = &loop;\n        cond_.notify_one();\n    }\n    loop.loop();    // 执行EventLoop的loop() 开启了底层的Poller的poll()\n    std::unique_lock<std::mutex> lock(mutex_);\n    loop_ = nullptr;\n}"
  },
  {
    "path": "EventLoopThread.h",
    "content": "#pragma once\n\n#include <functional>\n#include <mutex>\n#include <condition_variable>\n#include <string>\n\n#include \"noncopyable.h\"\n#include \"Thread.h\"\n\nclass EventLoop;\n\nclass EventLoopThread : noncopyable\n{\npublic:\n    using ThreadInitCallback = std::function<void(EventLoop *)>;\n\n    EventLoopThread(const ThreadInitCallback &cb = ThreadInitCallback(),\n                    const std::string &name = std::string());\n    ~EventLoopThread();\n\n    EventLoop *startLoop();\n\nprivate:\n    void threadFunc();\n\n    EventLoop *loop_;\n    bool exiting_;\n    Thread thread_;\n    std::mutex mutex_;             // 互斥锁\n    std::condition_variable cond_; // 条件变量\n    ThreadInitCallback callback_;\n};"
  },
  {
    "path": "EventLoopThreadPool.cc",
    "content": "#include <memory>\n\n#include \"EventLoopThreadPool.h\"\n#include \"EventLoopThread.h\"\n\nEventLoopThreadPool::EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg)\n    : baseLoop_(baseLoop)\n    , name_(nameArg)\n    , started_(false)\n    , numThreads_(0)\n    , next_(0)\n{\n}\n\nEventLoopThreadPool::~EventLoopThreadPool()\n{\n    // Don't delete loop, it's stack variable\n}\n\nvoid EventLoopThreadPool::start(const ThreadInitCallback &cb)\n{\n    started_ = true;\n\n    for(int i = 0; i < numThreads_; ++i)\n    {\n        char buf[name_.size() + 32];\n        snprintf(buf, sizeof buf, \"%s%d\", name_.c_str(), i);\n        EventLoopThread *t = new EventLoopThread(cb, buf);\n        threads_.push_back(std::unique_ptr<EventLoopThread>(t));\n        loops_.push_back(t->startLoop());                           // 底层创建线程 绑定一个新的EventLoop 并返回该loop的地址\n    }\n\n    if(numThreads_ == 0 && cb)                                      // 整个服务端只有一个线程运行baseLoop\n    {\n        cb(baseLoop_);\n    }\n}\n\n// 如果工作在多线程中，baseLoop_(mainLoop)会默认以轮询的方式分配Channel给subLoop\nEventLoop *EventLoopThreadPool::getNextLoop()\n{\n    EventLoop *loop = baseLoop_;    // 如果只设置一个线程 也就是只有一个mainReactor 无subReactor 那么轮询只有一个线程 getNextLoop()每次都返回当前的baseLoop_\n\n    if(!loops_.empty())             // 通过轮询获取下一个处理事件的loop\n    {\n        loop = loops_[next_];\n        ++next_;\n        if(next_ >= loops_.size())\n        {\n            next_ = 0;\n        }\n    }\n\n    return loop;\n}\n\nstd::vector<EventLoop *> EventLoopThreadPool::getAllLoops()\n{\n    if(loops_.empty())\n    {\n        return std::vector<EventLoop *>(1, baseLoop_);\n    }\n    else\n    {\n        return loops_;\n    }\n}"
  },
  {
    "path": "EventLoopThreadPool.h",
    "content": "#pragma once\n\n#include <functional>\n#include <string>\n#include <vector>\n#include <memory>\n\n#include \"noncopyable.h\"\n\nclass EventLoop;\nclass EventLoopThread;\n\nclass EventLoopThreadPool : noncopyable\n{\npublic:\n    using ThreadInitCallback = std::function<void(EventLoop *)>;\n\n    EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg);\n    ~EventLoopThreadPool();\n\n    void setThreadNum(int numThreads) { numThreads_ = numThreads; }\n\n    void start(const ThreadInitCallback &cb = ThreadInitCallback());\n\n    // 如果工作在多线程中，baseLoop_(mainLoop)会默认以轮询的方式分配Channel给subLoop\n    EventLoop *getNextLoop();\n\n    std::vector<EventLoop *> getAllLoops();\n\n    bool started() const { return started_; }\n    const std::string name() const { return name_; }\n\nprivate:\n    EventLoop *baseLoop_; // 用户使用muduo创建的loop 如果线程数为1 那直接使用用户创建的loop 否则创建多EventLoop\n    std::string name_;\n    bool started_;\n    int numThreads_;\n    int next_; // 轮询的下标\n    std::vector<std::unique_ptr<EventLoopThread>> threads_;\n    std::vector<EventLoop *> loops_;\n};"
  },
  {
    "path": "InetAddress.cc",
    "content": "#include <strings.h>\n#include <string.h>\n\n#include \"InetAddress.h\"\n\nInetAddress::InetAddress(uint16_t port, std::string ip)\n{\n    ::memset(&addr_, 0, sizeof(addr_));\n    addr_.sin_family = AF_INET;\n    addr_.sin_port = ::htons(port); // 本地字节序转为网络字节序\n    addr_.sin_addr.s_addr = ::inet_addr(ip.c_str());\n}\n\nstd::string InetAddress::toIp() const\n{\n    // addr_\n    char buf[64] = {0};\n    ::inet_ntop(AF_INET, &addr_.sin_addr, buf, sizeof buf);\n    return buf;\n}\n\nstd::string InetAddress::toIpPort() const\n{\n    // ip:port\n    char buf[64] = {0};\n    ::inet_ntop(AF_INET, &addr_.sin_addr, buf, sizeof buf);\n    size_t end = ::strlen(buf);\n    uint16_t port = ::ntohs(addr_.sin_port);\n    sprintf(buf+end, \":%u\", port);\n    return buf;\n}\n\nuint16_t InetAddress::toPort() const\n{\n    return ::ntohs(addr_.sin_port);\n}\n\n#if 0\n#include <iostream>\nint main()\n{\n    InetAddress addr(8080);\n    std::cout << addr.toIpPort() << std::endl;\n}\n#endif"
  },
  {
    "path": "InetAddress.h",
    "content": "#pragma once\n\n#include <arpa/inet.h>\n#include <netinet/in.h>\n#include <string>\n\n// 封装socket地址类型\nclass InetAddress\n{\npublic:\n    explicit InetAddress(uint16_t port = 0, std::string ip = \"127.0.0.1\");\n    explicit InetAddress(const sockaddr_in &addr)\n        : addr_(addr)\n    {\n    }\n\n    std::string toIp() const;\n    std::string toIpPort() const;\n    uint16_t toPort() const;\n\n    const sockaddr_in *getSockAddr() const { return &addr_; }\n    void setSockAddr(const sockaddr_in &addr) { addr_ = addr; }\n\nprivate:\n    sockaddr_in addr_;\n};"
  },
  {
    "path": "Logger.cc",
    "content": "#include <iostream>\n\n#include \"Logger.h\"\n#include \"Timestamp.h\"\n\n// 获取日志唯一的实例对象 单例\nLogger &Logger::instance()\n{\n    static Logger logger;\n    return logger;\n}\n\n// 设置日志级别\nvoid Logger::setLogLevel(int level)\n{\n    logLevel_ = level;\n}\n\n// 写日志 [级别信息] time : msg\nvoid Logger::log(std::string msg)\n{\n    std::string pre = \"\";\n    switch (logLevel_)\n    {\n    case INFO:\n        pre = \"[INFO]\";\n        break;\n    case ERROR:\n        pre = \"[ERROR]\";\n        break;\n    case FATAL:\n        pre = \"[FATAL]\";\n        break;\n    case DEBUG:\n        pre = \"[DEBUG]\";\n        break;\n    default:\n        break;\n    }\n\n    // 打印时间和msg\n    std::cout << pre + Timestamp::now().toString() << \" : \" << msg << std::endl;\n}"
  },
  {
    "path": "Logger.h",
    "content": "#pragma once\n\n#include <string>\n\n#include \"noncopyable.h\"\n\n// LOG_INFO(\"%s %d\", arg1, arg2)\n#define LOG_INFO(logmsgFormat, ...)                       \\\n    do                                                    \\\n    {                                                     \\\n        Logger &logger = Logger::instance();              \\\n        logger.setLogLevel(INFO);                         \\\n        char buf[1024] = {0};                             \\\n        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \\\n        logger.log(buf);                                  \\\n    } while (0)\n\n#define LOG_ERROR(logmsgFormat, ...)                      \\\n    do                                                    \\\n    {                                                     \\\n        Logger &logger = Logger::instance();              \\\n        logger.setLogLevel(ERROR);                        \\\n        char buf[1024] = {0};                             \\\n        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \\\n        logger.log(buf);                                  \\\n    } while (0)\n\n#define LOG_FATAL(logmsgFormat, ...)                      \\\n    do                                                    \\\n    {                                                     \\\n        Logger &logger = Logger::instance();              \\\n        logger.setLogLevel(FATAL);                        \\\n        char buf[1024] = {0};                             \\\n        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \\\n        logger.log(buf);                                  \\\n        exit(-1);                                         \\\n    } while (0)\n\n#ifdef MUDEBUG\n#define LOG_DEBUG(logmsgFormat, ...)                      \\\n    do                                                    \\\n    {                                                     \\\n        Logger &logger = Logger::instance();              \\\n        logger.setLogLevel(DEBUG);                        \\\n        char buf[1024] = {0};                             \\\n        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \\\n        logger.log(buf);                                  \\\n    } while (0)\n#else\n#define LOG_DEBUG(logmsgFormat, ...)\n#endif\n\n// 定义日志的级别 INFO ERROR FATAL DEBUG\nenum LogLevel\n{\n    INFO,  // 普通信息\n    ERROR, // 错误信息\n    FATAL, // core dump信息\n    DEBUG, // 调试信息\n};\n\n// 输出一个日志类\n\nclass Logger : noncopyable\n{\npublic:\n    // 获取日志唯一的实例对象 单例\n    static Logger &instance();\n    // 设置日志级别\n    void setLogLevel(int level);\n    // 写日志\n    void log(std::string msg);\n\nprivate:\n    int logLevel_;\n};"
  },
  {
    "path": "Poller.cc",
    "content": "#include \"Poller.h\"\n#include \"Channel.h\"\n\nPoller::Poller(EventLoop *loop)\n    : ownerLoop_(loop)\n{\n}\n\nbool Poller::hasChannel(Channel *channel) const\n{\n    auto it = channels_.find(channel->fd());\n    return it != channels_.end() && it->second == channel;\n}"
  },
  {
    "path": "Poller.h",
    "content": "#pragma once\n\n#include <vector>\n#include <unordered_map>\n\n#include \"noncopyable.h\"\n#include \"Timestamp.h\"\n\nclass Channel;\nclass EventLoop;\n\n// muduo库中多路事件分发器的核心IO复用模块\nclass Poller\n{\npublic:\n    using ChannelList = std::vector<Channel *>;\n\n    Poller(EventLoop *loop);\n    virtual ~Poller() = default;\n\n    // 给所有IO复用保留统一的接口\n    virtual Timestamp poll(int timeoutMs, ChannelList *activeChannels) = 0;\n    virtual void updateChannel(Channel *channel) = 0;\n    virtual void removeChannel(Channel *channel) = 0;\n\n    // 判断参数channel是否在当前的Poller当中\n    bool hasChannel(Channel *channel) const;\n\n    // EventLoop可以通过该接口获取默认的IO复用的具体实现\n    static Poller *newDefaultPoller(EventLoop *loop);\n\nprotected:\n    // map的key:sockfd value:sockfd所属的channel通道类型\n    using ChannelMap = std::unordered_map<int, Channel *>;\n    ChannelMap channels_;\n\nprivate:\n    EventLoop *ownerLoop_; // 定义Poller所属的事件循环EventLoop\n};"
  },
  {
    "path": "README.md",
    "content": "# C++11 Muduo\n\n![流程图](./img/a.png)\n\n## 开发环境\n\n* linux kernel version 4.4.0 (ubuntu 16.04 Server)\n* gcc version 5.4.0\n* cmake version 3.5.1\n\n项目编译执行`./build.sh`即可，测试用例进入`example/`文件夹，`make`即可生成服务器测试用例\n\n## 功能介绍\n\n头文件生成至目录`/usr/include/mymuduo/`，`.so`库文件生成至目录`/usr/lib/`。\n\n1. `EventLoop.*`、`Channel.*`、`Poller.*`、`EPollPoller.*`等主要用于事件轮询检测，并实现了事件分发处理的底层实现方法。`EventLoop`负责轮询执行`Poller`，要进行读、写、错误、关闭等事件时需执行哪些回调函数，均绑定至`Channel`中，只需从中调用即可，事件发生后进行相应的回调处理即可\n2. `Thread.*`、`EventLoopThread.*`、`EventLoopThreadPool.*`等将线程和`EventLoop`事件轮询绑定在一起，实现真正意义上的`one loop per thread`\n3. `TcpServer.*`、`TcpConnection.*`、`Acceptor.*`、`Socket.*`等是`mainloop`对网络连接的响应并轮询分发至各个`subloop`的实现，其中注册大量回调函数\n4. `Buffer.*`为`muduo`网络库自行设计的自动扩容的缓冲区，保证数据有序性到达\n\n\n## 技术亮点\n\n1. `EventLoop`中使用了`eventfd`来调用`wakeup()`，让`mainloop`唤醒`subloop`的`epoll_wait`阻塞\n2. 在`EventLoop`中注册回调`cb`至`pendingFunctors_`，并在`doPendingFunctors`中通过`swap()`的方式，快速换出注册的回调，只在`swap()`时加锁，减少代码临界区长度，提升效率。（若不通过`swap()`的方式去处理，而是加锁执行`pendingFunctors`中的回调，然后解锁，会出现什么问题呢？1. 临界区过大，锁降低了服务器响应效率 2. 若执行的回调中执行`queueInLoop`需要抢占锁时，会发生死锁）\n3. `Logger`可以设置日志等级，调试代码时可以开启`DEBUG`打印日志；若启动服务器，由于日志会影响服务器性能，可适当关闭`DEBUG`相关日志输出\n4. 在`Thread`中通过`C++lambda`表达式以及信号量机制保证线程创建时的有序性，只有当线程获取到了其自己的`tid`后，才算启动线程完毕\n5. `TcpConnection`继承自`enable_shared_from_this`，`TcpConnection`对象可以调用`shared_from_this()`方法给其内部回调函数，相当于创建了一个带引用计数的`shared_ptr`，可参考链接 [link](https://blog.csdn.net/gc348342215/article/details/123215888)，同时`muduo`通过`tie()`方式解决了`TcpConnection`对象生命周期先于`Channel`结束的情况\n6. `muduo`采用`Reactor`模型和多线程结合的方式，实现了高并发非阻塞网络库\n\n\n## 视频介绍\n\n* [muduo源码剖析(1)-简介](https://www.bilibili.com/video/BV1nu411Q7Gq)\n* [muduo源码剖析(2)-muduo编写回射服务器实例](https://www.bilibili.com/video/BV1CY411g7AE)\n* [muduo源码剖析(3)-Timestamp类日志类](https://www.bilibili.com/video/BV1dF411x7A8)\n* [muduo源码剖析(4)-Channel类](https://www.bilibili.com/video/BV14a411h7JW)\n* [muduo源码剖析(5)-Poller类、EPollPoller类等相关](https://www.bilibili.com/video/BV1VL4y1u714)\n* [muduo源码剖析(6)-EventLoop类介绍1](https://www.bilibili.com/video/BV1aY411g7As)\n* [muduo源码剖析(7)-EventLoop类介绍2](https://www.bilibili.com/video/BV1kS4y1S7DC)\n* [muduo源码剖析(8)-Thread类、EventLoopThread类](https://www.bilibili.com/video/BV1GL411P73C)\n* [muduo源码剖析(9)-EventLoopThreadPool类](https://www.bilibili.com/video/BV1yS4y1S7FY)\n* [muduo源码剖析(10)-InetAddress类、Socket类](https://www.bilibili.com/video/BV1UU4y1o7BT)\n* [muduo源码剖析(11)-Acceptor类1](https://www.bilibili.com/video/BV1q3411W79d)\n* [muduo源码剖析(12)-Acceptor类2](https://www.bilibili.com/video/BV1Ua411b7aV)\n* [muduo源码剖析(13)-TcpConnection类、Buffer类](https://www.bilibili.com/video/BV1hS4y137Eg)\n* [muduo源码剖析(14)-TcpConnection类、Buffer类2](https://www.bilibili.com/video/BV1PS4y1D74z)\n* [muduo源码剖析(15)-TcpConnection类](https://www.bilibili.com/video/BV1L3411p7jy)\n* [muduo源码剖析(16)-TcpServer类](https://www.bilibili.com/video/BV13Y411u74h)\n\n持续更新..\n"
  },
  {
    "path": "Socket.cc",
    "content": "#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <string.h>\n#include <netinet/tcp.h>\n#include <sys/socket.h>\n\n#include \"Socket.h\"\n#include \"Logger.h\"\n#include \"InetAddress.h\"\n\nSocket::~Socket()\n{\n    ::close(sockfd_);\n}\n\nvoid Socket::bindAddress(const InetAddress &localaddr)\n{\n    if (0 != ::bind(sockfd_, (sockaddr *)localaddr.getSockAddr(), sizeof(sockaddr_in)))\n    {\n        LOG_FATAL(\"bind sockfd:%d fail\\n\", sockfd_);\n    }\n}\n\nvoid Socket::listen()\n{\n    if (0 != ::listen(sockfd_, 1024))\n    {\n        LOG_FATAL(\"listen sockfd:%d fail\\n\", sockfd_);\n    }\n}\n\nint Socket::accept(InetAddress *peeraddr)\n{\n    /**\n     * 1. accept函数的参数不合法\n     * 2. 对返回的connfd没有设置非阻塞\n     * Reactor模型 one loop per thread\n     * poller + non-blocking IO\n     **/\n    sockaddr_in addr;\n    socklen_t len = sizeof(addr);\n    ::memset(&addr, 0, sizeof(addr));\n    // fixed : int connfd = ::accept(sockfd_, (sockaddr *)&addr, &len);\n    int connfd = ::accept4(sockfd_, (sockaddr *)&addr, &len, SOCK_NONBLOCK | SOCK_CLOEXEC);\n    if (connfd >= 0)\n    {\n        peeraddr->setSockAddr(addr);\n    }\n    return connfd;\n}\n\nvoid Socket::shutdownWrite()\n{\n    if (::shutdown(sockfd_, SHUT_WR) < 0)\n    {\n        LOG_ERROR(\"shutdownWrite error\");\n    }\n}\n\nvoid Socket::setTcpNoDelay(bool on)\n{\n    int optval = on ? 1 : 0;\n    ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)); // TCP_NODELAY包含头文件 <netinet/tcp.h>\n}\nvoid Socket::setReuseAddr(bool on)\n{\n    int optval = on ? 1 : 0;\n    ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // TCP_NODELAY包含头文件 <netinet/tcp.h>\n}\nvoid Socket::setReusePort(bool on)\n{\n    int optval = on ? 1 : 0;\n    ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); // TCP_NODELAY包含头文件 <netinet/tcp.h>\n}\nvoid Socket::setKeepAlive(bool on)\n{\n    int optval = on ? 1 : 0;\n    ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)); // TCP_NODELAY包含头文件 <netinet/tcp.h>\n}"
  },
  {
    "path": "Socket.h",
    "content": "#pragma once\n\n#include \"noncopyable.h\"\n\nclass InetAddress;\n\n// 封装socket fd\nclass Socket : noncopyable\n{\npublic:\n    explicit Socket(int sockfd)\n        : sockfd_(sockfd)\n    {\n    }\n    ~Socket();\n\n    int fd() const { return sockfd_; }\n    void bindAddress(const InetAddress &localaddr);\n    void listen();\n    int accept(InetAddress *peeraddr);\n\n    void shutdownWrite();\n\n    void setTcpNoDelay(bool on);\n    void setReuseAddr(bool on);\n    void setReusePort(bool on);\n    void setKeepAlive(bool on);\n\nprivate:\n    const int sockfd_;\n};\n"
  },
  {
    "path": "TcpConnection.cc",
    "content": "#include <functional>\n#include <string>\n#include <errno.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <string.h>\n#include <netinet/tcp.h>\n\n#include \"TcpConnection.h\"\n#include \"Logger.h\"\n#include \"Socket.h\"\n#include \"Channel.h\"\n#include \"EventLoop.h\"\n\nstatic EventLoop *CheckLoopNotNull(EventLoop *loop)\n{\n    if (loop == nullptr)\n    {\n        LOG_FATAL(\"%s:%s:%d mainLoop is null!\\n\", __FILE__, __FUNCTION__, __LINE__);\n    }\n    return loop;\n}\n\nTcpConnection::TcpConnection(EventLoop *loop,\n                             const std::string &nameArg,\n                             int sockfd,\n                             const InetAddress &localAddr,\n                             const InetAddress &peerAddr)\n    : loop_(CheckLoopNotNull(loop))\n    , name_(nameArg)\n    , state_(kConnecting)\n    , reading_(true)\n    , socket_(new Socket(sockfd))\n    , channel_(new Channel(loop, sockfd))\n    , localAddr_(localAddr)\n    , peerAddr_(peerAddr)\n    , highWaterMark_(64 * 1024 * 1024) // 64M\n{\n    // 下面给channel设置相应的回调函数 poller给channel通知感兴趣的事件发生了 channel会回调相应的回调函数\n    channel_->setReadCallback(\n        std::bind(&TcpConnection::handleRead, this, std::placeholders::_1));\n    channel_->setWriteCallback(\n        std::bind(&TcpConnection::handleWrite, this));\n    channel_->setCloseCallback(\n        std::bind(&TcpConnection::handleClose, this));\n    channel_->setErrorCallback(\n        std::bind(&TcpConnection::handleError, this));\n\n    LOG_INFO(\"TcpConnection::ctor[%s] at fd=%d\\n\", name_.c_str(), sockfd);\n    socket_->setKeepAlive(true);\n}\n\nTcpConnection::~TcpConnection()\n{\n    LOG_INFO(\"TcpConnection::dtor[%s] at fd=%d state=%d\\n\", name_.c_str(), channel_->fd(), (int)state_);\n}\n\nvoid TcpConnection::send(const std::string &buf)\n{\n    if (state_ == kConnected)\n    {\n        if (loop_->isInLoopThread()) // 这种是对于单个reactor的情况 用户调用conn->send时 loop_即为当前线程\n        {\n            sendInLoop(buf.c_str(), buf.size());\n        }\n        else\n        {\n            loop_->runInLoop(\n                std::bind(&TcpConnection::sendInLoop, this, buf.c_str(), buf.size()));\n        }\n    }\n}\n\n/**\n * 发送数据 应用写的快 而内核发送数据慢 需要把待发送数据写入缓冲区，而且设置了水位回调\n **/\nvoid TcpConnection::sendInLoop(const void *data, size_t len)\n{\n    ssize_t nwrote = 0;\n    size_t remaining = len;\n    bool faultError = false;\n\n    if (state_ == kDisconnected) // 之前调用过该connection的shutdown 不能再进行发送了\n    {\n        LOG_ERROR(\"disconnected, give up writing\");\n    }\n\n    // 表示channel_第一次开始写数据或者缓冲区没有待发送数据\n    if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0)\n    {\n        nwrote = ::write(channel_->fd(), data, len);\n        if (nwrote >= 0)\n        {\n            remaining = len - nwrote;\n            if (remaining == 0 && writeCompleteCallback_)\n            {\n                // 既然在这里数据全部发送完成，就不用再给channel设置epollout事件了\n                loop_->queueInLoop(\n                    std::bind(writeCompleteCallback_, shared_from_this()));\n            }\n        }\n        else // nwrote < 0\n        {\n            nwrote = 0;\n            if (errno != EWOULDBLOCK) // EWOULDBLOCK表示非阻塞情况下没有数据后的正常返回 等同于EAGAIN\n            {\n                LOG_ERROR(\"TcpConnection::sendInLoop\");\n                if (errno == EPIPE || errno == ECONNRESET) // SIGPIPE RESET\n                {\n                    faultError = true;\n                }\n            }\n        }\n    }\n    /**\n     * 说明当前这一次write并没有把数据全部发送出去 剩余的数据需要保存到缓冲区当中\n     * 然后给channel注册EPOLLOUT事件，Poller发现tcp的发送缓冲区有空间后会通知\n     * 相应的sock->channel，调用channel对应注册的writeCallback_回调方法，\n     * channel的writeCallback_实际上就是TcpConnection设置的handleWrite回调，\n     * 把发送缓冲区outputBuffer_的内容全部发送完成\n     **/\n    if (!faultError && remaining > 0)\n    {\n        // 目前发送缓冲区剩余的待发送的数据的长度\n        size_t oldLen = outputBuffer_.readableBytes();\n        if (oldLen + remaining >= highWaterMark_ && oldLen < highWaterMark_ && highWaterMarkCallback_)\n        {\n            loop_->queueInLoop(\n                std::bind(highWaterMarkCallback_, shared_from_this(), oldLen + remaining));\n        }\n        outputBuffer_.append((char *)data + nwrote, remaining);\n        if (!channel_->isWriting())\n        {\n            channel_->enableWriting(); // 这里一定要注册channel的写事件 否则poller不会给channel通知epollout\n        }\n    }\n}\n\nvoid TcpConnection::shutdown()\n{\n    if (state_ == kConnected)\n    {\n        setState(kDisconnecting);\n        loop_->runInLoop(\n            std::bind(&TcpConnection::shutdownInLoop, this));\n    }\n}\n\nvoid TcpConnection::shutdownInLoop()\n{\n    if (!channel_->isWriting()) // 说明当前outputBuffer_的数据全部向外发送完成\n    {\n        socket_->shutdownWrite();\n    }\n}\n\n// 连接建立\nvoid TcpConnection::connectEstablished()\n{\n    setState(kConnected);\n    channel_->tie(shared_from_this());\n    channel_->enableReading(); // 向poller注册channel的EPOLLIN读事件\n\n    // 新连接建立 执行回调\n    connectionCallback_(shared_from_this());\n}\n// 连接销毁\nvoid TcpConnection::connectDestroyed()\n{\n    if (state_ == kConnected)\n    {\n        setState(kDisconnected);\n        channel_->disableAll(); // 把channel的所有感兴趣的事件从poller中删除掉\n        connectionCallback_(shared_from_this());\n    }\n    channel_->remove(); // 把channel从poller中删除掉\n}\n\n// 读是相对服务器而言的 当对端客户端有数据到达 服务器端检测到EPOLLIN 就会触发该fd上的回调 handleRead取读走对端发来的数据\nvoid TcpConnection::handleRead(Timestamp receiveTime)\n{\n    int savedErrno = 0;\n    ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);\n    if (n > 0) // 有数据到达\n    {\n        // 已建立连接的用户有可读事件发生了 调用用户传入的回调操作onMessage shared_from_this就是获取了TcpConnection的智能指针\n        messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);\n    }\n    else if (n == 0) // 客户端断开\n    {\n        handleClose();\n    }\n    else // 出错了\n    {\n        errno = savedErrno;\n        LOG_ERROR(\"TcpConnection::handleRead\");\n        handleError();\n    }\n}\n\nvoid TcpConnection::handleWrite()\n{\n    if (channel_->isWriting())\n    {\n        int savedErrno = 0;\n        ssize_t n = outputBuffer_.writeFd(channel_->fd(), &savedErrno);\n        if (n > 0)\n        {\n            outputBuffer_.retrieve(n);\n            if (outputBuffer_.readableBytes() == 0)\n            {\n                channel_->disableWriting();\n                if (writeCompleteCallback_)\n                {\n                    // TcpConnection对象在其所在的subloop中 向pendingFunctors_中加入回调\n                    loop_->queueInLoop(\n                        std::bind(writeCompleteCallback_, shared_from_this()));\n                }\n                if (state_ == kDisconnecting)\n                {\n                    shutdownInLoop(); // 在当前所属的loop中把TcpConnection删除掉\n                }\n            }\n        }\n        else\n        {\n            LOG_ERROR(\"TcpConnection::handleWrite\");\n        }\n    }\n    else\n    {\n        LOG_ERROR(\"TcpConnection fd=%d is down, no more writing\", channel_->fd());\n    }\n}\n\nvoid TcpConnection::handleClose()\n{\n    LOG_INFO(\"TcpConnection::handleClose fd=%d state=%d\\n\", channel_->fd(), (int)state_);\n    setState(kDisconnected);\n    channel_->disableAll();\n\n    TcpConnectionPtr connPtr(shared_from_this());\n    connectionCallback_(connPtr); // 执行连接关闭的回调\n    closeCallback_(connPtr);      // 执行关闭连接的回调 执行的是TcpServer::removeConnection回调方法   // must be the last line\n}\n\nvoid TcpConnection::handleError()\n{\n    int optval;\n    socklen_t optlen = sizeof optval;\n    int err = 0;\n    if (::getsockopt(channel_->fd(), SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)\n    {\n        err = errno;\n    }\n    else\n    {\n        err = optval;\n    }\n    LOG_ERROR(\"TcpConnection::handleError name:%s - SO_ERROR:%d\\n\", name_.c_str(), err);\n}"
  },
  {
    "path": "TcpConnection.h",
    "content": "#pragma once\n\n#include <memory>\n#include <string>\n#include <atomic>\n\n#include \"noncopyable.h\"\n#include \"InetAddress.h\"\n#include \"Callbacks.h\"\n#include \"Buffer.h\"\n#include \"Timestamp.h\"\n\nclass Channel;\nclass EventLoop;\nclass Socket;\n\n/**\n * TcpServer => Acceptor => 有一个新用户连接，通过accept函数拿到connfd\n * => TcpConnection设置回调 => 设置到Channel => Poller => Channel回调\n **/\n\nclass TcpConnection : noncopyable, public std::enable_shared_from_this<TcpConnection>\n{\npublic:\n    TcpConnection(EventLoop *loop,\n                  const std::string &nameArg,\n                  int sockfd,\n                  const InetAddress &localAddr,\n                  const InetAddress &peerAddr);\n    ~TcpConnection();\n\n    EventLoop *getLoop() const { return loop_; }\n    const std::string &name() const { return name_; }\n    const InetAddress &localAddress() const { return localAddr_; }\n    const InetAddress &peerAddress() const { return peerAddr_; }\n\n    bool connected() const { return state_ == kConnected; }\n\n    // 发送数据\n    void send(const std::string &buf);\n    // 关闭连接\n    void shutdown();\n\n    void setConnectionCallback(const ConnectionCallback &cb)\n    { connectionCallback_ = cb; }\n    void setMessageCallback(const MessageCallback &cb)\n    { messageCallback_ = cb; }\n    void setWriteCompleteCallback(const WriteCompleteCallback &cb)\n    { writeCompleteCallback_ = cb; }\n    void setCloseCallback(const CloseCallback &cb)\n    { closeCallback_ = cb; }\n    void setHighWaterMarkCallback(const HighWaterMarkCallback &cb, size_t highWaterMark)\n    { highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark; }\n\n    // 连接建立\n    void connectEstablished();\n    // 连接销毁\n    void connectDestroyed();\n\nprivate:\n    enum StateE\n    {\n        kDisconnected, // 已经断开连接\n        kConnecting,   // 正在连接\n        kConnected,    // 已连接\n        kDisconnecting // 正在断开连接\n    };\n    void setState(StateE state) { state_ = state; }\n\n    void handleRead(Timestamp receiveTime);\n    void handleWrite();\n    void handleClose();\n    void handleError();\n\n    void sendInLoop(const void *data, size_t len);\n    void shutdownInLoop();\n\n    EventLoop *loop_; // 这里是baseloop还是subloop由TcpServer中创建的线程数决定 若为多Reactor 该loop_指向subloop 若为单Reactor 该loop_指向baseloop\n    const std::string name_;\n    std::atomic_int state_;\n    bool reading_;\n\n    // Socket Channel 这里和Acceptor类似    Acceptor => mainloop    TcpConnection => subloop\n    std::unique_ptr<Socket> socket_;\n    std::unique_ptr<Channel> channel_;\n\n    const InetAddress localAddr_;\n    const InetAddress peerAddr_;\n\n    // 这些回调TcpServer也有 用户通过写入TcpServer注册 TcpServer再将注册的回调传递给TcpConnection TcpConnection再将回调注册到Channel中\n    ConnectionCallback connectionCallback_;       // 有新连接时的回调\n    MessageCallback messageCallback_;             // 有读写消息时的回调\n    WriteCompleteCallback writeCompleteCallback_; // 消息发送完成以后的回调\n    HighWaterMarkCallback highWaterMarkCallback_;\n    CloseCallback closeCallback_;\n    size_t highWaterMark_;\n\n    // 数据缓冲区\n    Buffer inputBuffer_;    // 接收数据的缓冲区\n    Buffer outputBuffer_;   // 发送数据的缓冲区 用户send向outputBuffer_发\n};\n"
  },
  {
    "path": "TcpServer.cc",
    "content": "#include <functional>\n#include <string.h>\n\n#include \"TcpServer.h\"\n#include \"Logger.h\"\n#include \"TcpConnection.h\"\n\nstatic EventLoop *CheckLoopNotNull(EventLoop *loop)\n{\n    if (loop == nullptr)\n    {\n        LOG_FATAL(\"%s:%s:%d mainLoop is null!\\n\", __FILE__, __FUNCTION__, __LINE__);\n    }\n    return loop;\n}\n\nTcpServer::TcpServer(EventLoop *loop,\n                     const InetAddress &listenAddr,\n                     const std::string &nameArg,\n                     Option option)\n    : loop_(CheckLoopNotNull(loop))\n    , ipPort_(listenAddr.toIpPort())\n    , name_(nameArg)\n    , acceptor_(new Acceptor(loop, listenAddr, option == kReusePort))\n    , threadPool_(new EventLoopThreadPool(loop, name_))\n    , connectionCallback_()\n    , messageCallback_()\n    , nextConnId_(1)\n    , started_(0)\n{\n    // 当有新用户连接时，Acceptor类中绑定的acceptChannel_会有读事件发生，执行handleRead()调用TcpServer::newConnection回调\n    acceptor_->setNewConnectionCallback(\n        std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));\n}\n\nTcpServer::~TcpServer()\n{\n    for(auto &item : connections_)\n    {\n        TcpConnectionPtr conn(item.second);\n        item.second.reset();    // 把原始的智能指针复位 让栈空间的TcpConnectionPtr conn指向该对象 当conn出了其作用域 即可释放智能指针指向的对象\n        // 销毁连接\n        conn->getLoop()->runInLoop(\n            std::bind(&TcpConnection::connectDestroyed, conn));\n    }\n}\n\n// 设置底层subloop的个数\nvoid TcpServer::setThreadNum(int numThreads)\n{\n    threadPool_->setThreadNum(numThreads);\n}\n\n// 开启服务器监听\nvoid TcpServer::start()\n{\n    if (started_++ == 0)    // 防止一个TcpServer对象被start多次\n    {\n        threadPool_->start(threadInitCallback_);    // 启动底层的loop线程池\n        loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));\n    }\n}\n\n// 有一个新用户连接，acceptor会执行这个回调操作，负责将mainLoop接收到的请求连接(acceptChannel_会有读事件发生)通过回调轮询分发给subLoop去处理\nvoid TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)\n{\n    // 轮询算法 选择一个subLoop 来管理connfd对应的channel\n    EventLoop *ioLoop = threadPool_->getNextLoop();\n    char buf[64] = {0};\n    snprintf(buf, sizeof buf, \"-%s#%d\", ipPort_.c_str(), nextConnId_);\n    ++nextConnId_;  // 这里没有设置为原子类是因为其只在mainloop中执行 不涉及线程安全问题\n    std::string connName = name_ + buf;\n\n    LOG_INFO(\"TcpServer::newConnection [%s] - new connection [%s] from %s\\n\",\n             name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());\n    \n    // 通过sockfd获取其绑定的本机的ip地址和端口信息\n    sockaddr_in local;\n    ::memset(&local, 0, sizeof(local));\n    socklen_t addrlen = sizeof(local);\n    if(::getsockname(sockfd, (sockaddr *)&local, &addrlen) < 0)\n    {\n        LOG_ERROR(\"sockets::getLocalAddr\");\n    }\n\n    InetAddress localAddr(local);\n    TcpConnectionPtr conn(new TcpConnection(ioLoop,\n                                            connName,\n                                            sockfd,\n                                            localAddr,\n                                            peerAddr));\n    connections_[connName] = conn;\n    // 下面的回调都是用户设置给TcpServer => TcpConnection的，至于Channel绑定的则是TcpConnection设置的四个，handleRead,handleWrite... 这下面的回调用于handlexxx函数中\n    conn->setConnectionCallback(connectionCallback_);\n    conn->setMessageCallback(messageCallback_);\n    conn->setWriteCompleteCallback(writeCompleteCallback_);\n\n    // 设置了如何关闭连接的回调\n    conn->setCloseCallback(\n        std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));\n\n    ioLoop->runInLoop(\n        std::bind(&TcpConnection::connectEstablished, conn));\n}\n\nvoid TcpServer::removeConnection(const TcpConnectionPtr &conn)\n{\n    loop_->runInLoop(\n        std::bind(&TcpServer::removeConnectionInLoop, this, conn));\n}\n\nvoid TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn)\n{\n    LOG_INFO(\"TcpServer::removeConnectionInLoop [%s] - connection %s\\n\",\n             name_.c_str(), conn->name().c_str());\n\n    connections_.erase(conn->name());\n    EventLoop *ioLoop = conn->getLoop();\n    ioLoop->queueInLoop(\n        std::bind(&TcpConnection::connectDestroyed, conn));\n}"
  },
  {
    "path": "TcpServer.h",
    "content": "#pragma once\n\n/**\n * 用户使用muduo编写服务器程序\n **/\n\n#include <functional>\n#include <string>\n#include <memory>\n#include <atomic>\n#include <unordered_map>\n\n#include \"EventLoop.h\"\n#include \"Acceptor.h\"\n#include \"InetAddress.h\"\n#include \"noncopyable.h\"\n#include \"EventLoopThreadPool.h\"\n#include \"Callbacks.h\"\n#include \"TcpConnection.h\"\n#include \"Buffer.h\"\n\n// 对外的服务器编程使用的类\nclass TcpServer\n{\npublic:\n    using ThreadInitCallback = std::function<void(EventLoop *)>;\n\n    enum Option\n    {\n        kNoReusePort,\n        kReusePort,\n    };\n\n    TcpServer(EventLoop *loop,\n              const InetAddress &listenAddr,\n              const std::string &nameArg,\n              Option option = kNoReusePort);\n    ~TcpServer();\n\n    void setThreadInitCallback(const ThreadInitCallback &cb) { threadInitCallback_ = cb; }\n    void setConnectionCallback(const ConnectionCallback &cb) { connectionCallback_ = cb; }\n    void setMessageCallback(const MessageCallback &cb) { messageCallback_ = cb; }\n    void setWriteCompleteCallback(const WriteCompleteCallback &cb) { writeCompleteCallback_ = cb; }\n\n    // 设置底层subloop的个数\n    void setThreadNum(int numThreads);\n\n    // 开启服务器监听\n    void start();\n\nprivate:\n    void newConnection(int sockfd, const InetAddress &peerAddr);\n    void removeConnection(const TcpConnectionPtr &conn);\n    void removeConnectionInLoop(const TcpConnectionPtr &conn);\n\n    using ConnectionMap = std::unordered_map<std::string, TcpConnectionPtr>;\n\n    EventLoop *loop_; // baseloop 用户自定义的loop\n\n    const std::string ipPort_;\n    const std::string name_;\n\n    std::unique_ptr<Acceptor> acceptor_; // 运行在mainloop 任务就是监听新连接事件\n\n    std::shared_ptr<EventLoopThreadPool> threadPool_; // one loop per thread\n\n    ConnectionCallback connectionCallback_;       //有新连接时的回调\n    MessageCallback messageCallback_;             // 有读写事件发生时的回调\n    WriteCompleteCallback writeCompleteCallback_; // 消息发送完成后的回调\n\n    ThreadInitCallback threadInitCallback_; // loop线程初始化的回调\n\n    std::atomic_int started_;\n\n    int nextConnId_;\n    ConnectionMap connections_; // 保存所有的连接\n};"
  },
  {
    "path": "Thread.cc",
    "content": "#include \"Thread.h\"\n#include \"CurrentThread.h\"\n\n#include <semaphore.h>\n\nstd::atomic_int Thread::numCreated_(0);\n\nThread::Thread(ThreadFunc func, const std::string &name)\n    : started_(false)\n    , joined_(false)\n    , tid_(0)\n    , func_(std::move(func))\n    , name_(name)\n{\n    setDefaultName();\n}\n\nThread::~Thread()\n{\n    if (started_ && !joined_)\n    {\n        thread_->detach();                                                  // thread类提供了设置分离线程的方法 线程运行后自动销毁（非阻塞）\n    }\n}\n\nvoid Thread::start()                                                        // 一个Thread对象 记录的就是一个新线程的详细信息\n{\n    started_ = true;\n    sem_t sem;\n    sem_init(&sem, false, 0);                                               // false指的是 不设置进程间共享\n    // 开启线程\n    thread_ = std::shared_ptr<std::thread>(new std::thread([&]() {\n        tid_ = CurrentThread::tid();                                        // 获取线程的tid值\n        sem_post(&sem);\n        func_();                                                            // 开启一个新线程 专门执行该线程函数\n    }));\n\n    // 这里必须等待获取上面新创建的线程的tid值\n    sem_wait(&sem);\n}\n\n// C++ std::thread 中join()和detach()的区别：https://blog.nowcoder.net/n/8fcd9bb6e2e94d9596cf0a45c8e5858a\nvoid Thread::join()\n{\n    joined_ = true;\n    thread_->join();\n}\n\nvoid Thread::setDefaultName()\n{\n    int num = ++numCreated_;\n    if (name_.empty())\n    {\n        char buf[32] = {0};\n        snprintf(buf, sizeof buf, \"Thread%d\", num);\n        name_ = buf;\n    }\n}"
  },
  {
    "path": "Thread.h",
    "content": "#pragma once\n\n#include <functional>\n#include <thread>\n#include <memory>\n#include <unistd.h>\n#include <string>\n#include <atomic>\n\n#include \"noncopyable.h\"\n\nclass Thread : noncopyable\n{\npublic:\n    using ThreadFunc = std::function<void()>;\n\n    explicit Thread(ThreadFunc, const std::string &name = std::string());\n    ~Thread();\n\n    void start();\n    void join();\n\n    bool started() { return started_; }\n    pid_t tid() const { return tid_; }\n    const std::string &name() const { return name_; }\n\n    static int numCreated() { return numCreated_; }\n\nprivate:\n    void setDefaultName();\n\n    bool started_;\n    bool joined_;\n    std::shared_ptr<std::thread> thread_;\n    pid_t tid_;       // 在线程创建时再绑定\n    ThreadFunc func_; // 线程回调函数\n    std::string name_;\n    static std::atomic_int numCreated_;\n};"
  },
  {
    "path": "Timestamp.cc",
    "content": "#include <time.h>\n\n#include \"Timestamp.h\"\n\nTimestamp::Timestamp() : microSecondsSinceEpoch_(0)\n{\n}\n\nTimestamp::Timestamp(int64_t microSecondsSinceEpoch)\n    : microSecondsSinceEpoch_(microSecondsSinceEpoch)\n{\n}\n\nTimestamp Timestamp::now()\n{\n    return Timestamp(time(NULL));\n}\nstd::string Timestamp::toString() const\n{\n    char buf[128] = {0};\n    tm *tm_time = localtime(&microSecondsSinceEpoch_);\n    snprintf(buf, 128, \"%4d/%02d/%02d %02d:%02d:%02d\",\n             tm_time->tm_year + 1900,\n             tm_time->tm_mon + 1,\n             tm_time->tm_mday,\n             tm_time->tm_hour,\n             tm_time->tm_min,\n             tm_time->tm_sec);\n    return buf;\n}\n\n// #include <iostream>\n// int main() {\n//     std::cout << Timestamp::now().toString() << std::endl;\n//     return 0;\n// }"
  },
  {
    "path": "Timestamp.h",
    "content": "#pragma once\n\n#include <iostream>\n#include <string>\n\nclass Timestamp\n{\npublic:\n    Timestamp();\n    explicit Timestamp(int64_t microSecondsSinceEpoch);\n    static Timestamp now();\n    std::string toString() const;\n\nprivate:\n    int64_t microSecondsSinceEpoch_;\n};"
  },
  {
    "path": "build.sh",
    "content": "#!/bin/bash\n\nset -e\n\n# 如果没有build目录 创建该目录\nif [ ! -d `pwd`/build ]; then\n    mkdir `pwd`/build\nfi\n\nrm -fr `pwd`/build/*\ncd `pwd`/build &&\n    cmake .. &&\n    make\n\n# 回到项目根目录\ncd ..\n\n# 把头文件拷贝到 /usr/include/mymuduo       .so库拷贝到 /usr/lib\nif [ ! -d /usr/include/mymuduo ]; then\n    mkdir /usr/include/mymuduo\nfi\n\nfor header in `ls *.h`\ndo\n    cp $header /usr/include/mymuduo\ndone\n\ncp `pwd`/lib/libmymuduo.so /usr/lib\n\nldconfig"
  },
  {
    "path": "example/Makefile",
    "content": "testserver :\n\tg++ -g -o testserver testserver.cc -lmymuduo -lpthread -std=c++11\n\nclean :\n\trm -f testserver"
  },
  {
    "path": "example/testserver.cc",
    "content": "#include <string>\n\n#include <mymuduo/TcpServer.h>\n#include <mymuduo/Logger.h>\n\nclass EchoServer\n{\npublic:\n    EchoServer(EventLoop *loop, const InetAddress &addr, const std::string &name)\n        : server_(loop, addr, name)\n        , loop_(loop)\n    {\n        // 注册回调函数\n        server_.setConnectionCallback(\n            std::bind(&EchoServer::onConnection, this, std::placeholders::_1));\n        \n        server_.setMessageCallback(\n            std::bind(&EchoServer::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));\n\n        // 设置合适的subloop线程数量\n        server_.setThreadNum(3);\n    }\n    void start()\n    {\n        server_.start();\n    }\n\nprivate:\n    // 连接建立或断开的回调函数\n    void onConnection(const TcpConnectionPtr &conn)   \n    {\n        if (conn->connected())\n        {\n            LOG_INFO(\"Connection UP : %s\", conn->peerAddress().toIpPort().c_str());\n        }\n        else\n        {\n            LOG_INFO(\"Connection DOWN : %s\", conn->peerAddress().toIpPort().c_str());\n        }\n    }\n\n    // 可读写事件回调\n    void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time)\n    {\n        std::string msg = buf->retrieveAllAsString();\n        conn->send(msg);\n        // conn->shutdown();   // 关闭写端 底层响应EPOLLHUP => 执行closeCallback_\n    }\n\n    EventLoop *loop_;\n    TcpServer server_;\n};\n\nint main() {\n    EventLoop loop;\n    InetAddress addr(8002);\n    EchoServer server(&loop, addr, \"EchoServer\");\n    server.start();\n    loop.loop();\n    return 0;\n}"
  },
  {
    "path": "noncopyable.h",
    "content": "#pragma once // 防止头文件重复包含\n\n/**\n * noncopyable被继承后 派生类对象可正常构造和析构 但派生类对象无法进行拷贝构造和赋值构造\n **/\nclass noncopyable\n{\npublic:\n    noncopyable(const noncopyable &) = delete;\n    noncopyable &operator=(const noncopyable &) = delete;\n    // void operator=(const noncopyable &) = delete;    // muduo将返回值变为void 这其实无可厚非\nprotected:\n    noncopyable() = default;\n    ~noncopyable() = default;\n};"
  }
]