跳转至

callback

call in Channel

Channel中的回调函数如下:

    ReadEventCallback readCallback_;    // 可读事件到来时
    EventCallback     writeCallback_;   // 可写事件到来时
    EventCallback     closeCallback_;   // 关闭连接事件
    EventCallback     errorCallback_;   // 发生错误事件
Channel负责关注I/O事件,并且设置对应的事件回调函数。在muduo中用到的I/O有timerfdeventfdsocket。关于socket的事件回调函数在TcpConnection中实现,具体如下:
    channel_->setReadCallback( std::bind(&TcpConnection::handleRead,  this, _1));
    channel_->setWriteCallback(std::bind(&TcpConnection::handleWrite, this));
    channel_->setCloseCallback(std::bind(&TcpConnection::handleClose, this));
    channel_->setErrorCallback(std::bind(&TcpConnection::handleError, this));
+ setReadCallback:如果不关注这个事件,数据自然无法读取 + setWriteCallback:如果不关注这个,数据仅仅可以发送一次。 + setCloseCallback:

callback in TcpConnection

    ConnectionCallback    connectionCallback_;
    MessageCallback       messageCallback_;         // 有数据可读时。handleRead()内部
    WriteCompleteCallback writeCompleteCallback_;   // 数据写完时调用,handleWrite()、sendInLoop内部
    HighWaterMarkCallback highWaterMarkCallback_;   // 发送数据时用, sendInLoop 中 
    CloseCallback         closeCallback_;

handleWrite()

handleWrite()中需要使用highWaterMarkCallback_是因为,handleWrite()发送的是outputBuffer_中的数据,整个写的过程如下: 1. send()sendInLoop() → 先将要发送的数据尽可能多地填充满socket缓冲区 2. 如果socket不足以容纳全部的待发送数据,那么此时注册POLLOUT事件 3. 等到socket将其缓冲区的数据发送出去,其缓冲区为空,触发POLLOUT事件 4. 这时候触发handleWrite()事件,将outputBuffer_中的数据发送出去 5. 将outputBuffer_中数据发送完,就再次调用writeCompleteCallback_,那么在其内部肯定有send(...) 6. 如果第一步中,待发送的数据能够全部复制到socket缓冲区,那么就直接发送,不会触发handleWrite(),直接调用writeCompleteCallback_,在其内部调用send。 7. 重复上述步骤。

因此,如果没有关注Channel中的handleWrite()只要待发送的数据量大于socket的缓冲区,那么此后数据将无法再次发送。

handleRead()

对于messageCallback_是用在handleRead()中,为的是将socket中的数据提取到inputBuffer_中。而handleRead()如果没有关注: + 数据无法提取:那么epoll将一致通知用户去取,但是没有注册handleRead()函数,就会处于busy-loop + 无法应对peer的关闭操作,即无法被动关闭与某个客户端的连接,只能主动关闭。 + 无法处理错误

因此,在messageCallback_中应该要有获取inputBuffer_中的数据的操作,默认的messageCallback_

    void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, Buffer* buf, Timestamp) {
        buf->retrieveAll();
    }
只是将移动了readerIndex_writerIndex_到初始化位置,没有读取数据,相当于丢弃了数据。

handClose()

handleClose()搭配closeCallback_,在handleClose()中调用closeCallback_,而是由TcpServer的内部函数TcpServer::removeConnectionInLoop实现。当检测到有客户端关闭时,就会触发,关闭与客户端的连接。 + 对端关闭时,是触发handleRead()还是触发handClose()?

    // 只是写了核心部分
    void Channel::handleEventWithGuard(Timestamp receiveTime) {
        if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) {   
            if (logHup_) {
                LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";
            }
            if (closeCallback_) closeCallback_();  
        }
        if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) {
            if (readCallback_) readCallback_(receiveTime);
        }
    }
由于关闭操作,也会触发epollPOLLIN操作,是通过返回的标志位不同,来判断是直接调用closeCallback_,还是调用readCallback_中的closeCallback_
+ 注意: + Channel中的closeBack_TcpConnection中的closeCallback_只是表示一致,但是含义不同。 + TcpConnection中的closeCallback_TcpServer传入,而channel_的即handleClose()

callback in TcpServer

    ConnectionCallback      connectionCallback_;
    MessageCallback         messageCallback_;
    WriteCompleteCallback   writeCompleteCallback_;
TcpConnection中的五个回调函数都应该是由TcpServer传入,但是实际上muduo只是设置了四个,而highWaterMarkCallback_没有设置。
    void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) {
        ...
        connections_[connName] = conn;  /** 引用计数增加1,变成2*/
        conn->setConnectionCallback(connectionCallback_);
        conn->setMessageCallback(messageCallback_);
        conn->setWriteCompleteCallback(writeCompleteCallback_);
        conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, _1)); 
        ...
    }
其中前三个,由外部传入,最后一个是内部函数。其中前面两个还有默认的回调函数:
    void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn) {
        LOG_TRACE << conn->localAddress().toIpPort() << " -> "
                << conn->peerAddress().toIpPort() << " is "
                << (conn->connected() ? "UP" : "DOWN");
    }

    void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, Buffer* buf, Timestamp) {
        buf->retrieveAll();
    }
最后一个WriteCompleteCallback_需要自己从外部传入,其实highWaterMarkCallback_也需要自己从外部传入,但是muduo在建立新连接时没有设置。
 conn->setHighWaterMarkCallback(highWaterMarkCallback_); 

至此,socketI/O中的回调函数已经基本全部分析完毕。其余的两个timerfdeventfd对应的回调函数见第一个总结