服务端主动关闭连接,如何确保对端能够收到全部的数据?

本文是个人对本问题的分析(Muduo库),如有不对的地方请指正😄

主动关闭连接,如何确保对端收到数据?

问题:如果不是长连接的话,发送完毕数据之后应该是关闭连接,因此关闭连接需要确保数据发送完成

  1. 暂时使用sleep(1)等待数据发送完毕是可以的,但是这是绝对不允许的。用其他 同步机制? or 别的方法
  2. 不使用shutdown(…WR)而是关闭写端也是可以的,但是。。。。。
  3. send发送数据的内部会确保数据发送成功的,shutdown同时确认一下是否发送成功✅

解决:

首先发送数据是调用的TcpConnection::send()函数进行发送

发送的流程:

  1. 如果是第一次发送,缓冲区中没有数据,调用write进行发送,剩没发送完的余的数据放置到outputBuffer中(注册socket的写事件)
  2. 触发了写事件的回调(如果有数据没发送完),也就是将缓冲区的数据发送出去,直到发送完毕将写事件注销掉

发送数据的代码

void TcpConnection::send(const string& message) {
    int remain = message.size();
    int send_size = 0;
    // channel_第一次写数据(epoll没关注写时间),缓冲区不能有待发送的数据
    if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) {
        send_size = static_cast<int>(::write(channel_->fd(), message.data(), message.size()));
        if (send_size >= 0) {
            remain -= send_size;
        } else {
            if (errno != EWOULDBLOCK) {
                printf("TcpConnection::Send write failed\n");
            }
            return ;
        }
    }

    assert(remain <= message.size());
    if (remain > 0) {
        // 将剩余的数据写入buffer中, 要注意添加到之前还剩余的数据的后面
        outputBuffer_.append((char*)message.c_str() + send_size, remain);
        if (!channel_->isWriting()) {   // 如果没有关注写的事件
            printf("数据没发送完,放到buffer中,注册写事件\n");
            channel_->enableWriting();  // 注册写事件
        }
    }
}

void TcpConnection::send(Buffer* buffer) {    
    if (state_ == kConnected) {
        send(std::move(string(buffer->peek(), buffer->readableBytes())));
        buffer->retrieveAll();
    }
}

如何保证对端收到数据?

  1. 在关闭的时候会 判断一下socket是否是还是在EPOLLER中可写的状态(如果是可写的状态,那么久代表缓冲区还没写完呢), 如果不可写那么就代表缓冲区残留的没发送出去的数据(如果有)也发送完毕了

连接关闭的代码

void TcpConnection::shutdown()
{
    if(state_ == kConnected)
    {
        setState(kDisconnecting);
        // 在自己的线程中执行回调
        loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this));
    }
}

void TcpConnection::shutdownInLoop() {
    // 如果不可写,说明已经将发送缓冲区outputBuffer的数据发送完了, 保证数据发送完
    if(!channel_->isWriting())
    {
        // 关闭写端
        socket_->shutdownWrite();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值