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


    本文是个人对本问题的分析(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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    如何保证对端收到数据?

    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    “蔚来杯“2022牛客暑期多校训练营10
    【kafka】十二、Zookeeper在kafka中的作用
    长沙地铁一号线大客流运输组织优化研究
    自媒体人一般会从哪里找素材呢?
    vite+vue3.0 + TypeScript+element-plus环境搭建
    DL/ML/RL/TL/FL机器学习框架总结
    【Java - L - 0102】- m - 二叉树的层序遍历
    Markdown 画图学习
    【OpenCV实战】4.OpenCV 五种滤波使用实战(均值、盒状、中值、高斯、双边)
    学习笔记25--多传感器前融合技术
  • 原文地址:https://blog.csdn.net/qq_52245648/article/details/126529907