Muduo只有一种关闭连接的方式:被动关闭,即对方先关闭连接
当TcpConnection在处理读事件时(handleRead),当read接口返回的长度为0时,触发关闭逻辑。
void TcpConnection::handleRead()
{
char buf[65536];
ssize_t n = ::read(channel_->fd(), buf, sizeof buf);
if (n > 0) {
messageCallback_(shared_from_this(), buf, n);
} else if (n == 0) { //n为0,表明对方已关闭连接
handleClose();
} else {
handleError();
}
}
handleClose通知TcpServer关闭连接
void TcpConnection::handleClose()
{
loop_->assertInLoopThread();
assert(state_ == kConnected);
// we don't close fd, leave it to dtor, so we can find leaks easily.
channel_->disableAll();
// 通知TcpServer关闭连接
closeCallback_(shared_from_this());
}
TcpServer先在map中删除该连接对应的键值对,然后再通知EvevtLoop对象调用TcpConnection::connectDestroyed方法
void TcpServer::removeConnection(const TcpConnectionPtr& conn)
{
loop_->assertInLoopThread();
size_t n = connections_.erase(conn->name());
loop_->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}
connectDestroyed先关闭对channel上的事件的监听,然后通知上层连接已关闭,最后删除poller对象中的channel对象
void TcpConnection::connectDestroyed()
{
loop_->assertInLoopThread();
assert(state_ == kConnected);
setState(kDisconnected);
channel_->disableAll(); //关闭掉channel对事件的监听
connectionCallback_(shared_from_this()); //通知上层连接已关闭
loop_->removeChannel(channel_.get()); //删除poller对象中的channel
}
Poller对象中删除channel对象的逻辑如下:
void Poller::removeChannel(Channel* channel)
{
assertInLoopThread();
int idx = channel->index();
const struct pollfd& pfd = pollfds_[idx];
size_t n = channels_.erase(channel->fd()); //1、先删除map中的<fd, channel>键值对
if (implicit_cast<size_t>(idx) == pollfds_.size()-1) {
pollfds_.pop_back(); //2、如果在vector尾部直接删除
} else {
int channelAtEnd = pollfds_.back().fd; //3、如果不在尾部,先与尾部元素交换后再删除,避免了vector中元素的移动
iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);
if (channelAtEnd < 0) {
channelAtEnd = -channelAtEnd-1;
}
channels_[channelAtEnd]->set_index(idx);
pollfds_.pop_back();
}
}
网友评论