仿muduo库实现高并发服务器----通信链接管理Connection

目录

一、目的

二、功能设计

三、功能

四、成员函数


一、目的

对链接进行全方位的管理,对通信链接的所有操作都是通过这个模块提供的功能实现的

二、功能设计

1、套接字的管理,能够进行套接字的操作

2、链接事件的管理,可读可写错误挂断任意

3、缓冲区的管理,便于Socket数据的接收和发送

4、上下文的管理,记录请求数据的处理过程

5、回调函数 因为链接收到数据之后该如何处理,需要由用户决定,因此必须有业务处理回调函数,一个链接建立成功后,该如何处理,一个链接关闭应该如何处理都需要回调函数

三、功能

1、发送数据:并不是真正的发送数据,只是把数据放到发送缓冲区中,然后启动写事件回调

2、关闭链接: 给用户提供关闭链接接口,在关闭释放链接之前,看看输入输出缓冲区是否有数据待处理

3、启动非活跃链接的超时销毁功能

4、取消非活跃链接的超时销毁功能

5、协议切换

注意:为了防止对链接进行操作的时候,但是链接已经被释放,导致内存访问错误,最终导致程序崩溃,我们使用智能指针shared_ptr对Connection对象进行操作的时候报存一个shared_ptr,就算在别的地方进行释放操作,也只是对shared_ptr-1;

cpp 复制代码
using PtrConnection = std::shared_ptr<Connection>;

四、成员函数

链接的唯一id,便于链接管理和查找 uint64_t _conn_id;

链接关联的文件描述符 int _sockfd;

套接字操作管理 Socket

链接的事件管理 Channel _channel

输入缓冲区,输出缓冲区 Buffer _in_buffer; Buffer _out_buffer;

请求处理上下文 Any _context

此时的状态 Connstatu _statu;

是否启动非活跃链接 bool _enable_inactive_release;

链接关联的Eventloop

四个回调事件

cpp 复制代码
 using ConnectedCallback = std::function<void(const PtrConnection &)>;
    using MessageCallback = std::function<void(const PtrConnection &, Buffer *)>;
    using ClosedCallback = std::function<void(const PtrConnection &)>;
    using AnyEventCallback = std::function<void(const PtrConnection &)>;
    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    ClosedCallback _server_closed_callback;
    AnyEventCallback _event_callback;

整体

cpp 复制代码
 using PtrConnection = std::shared_ptr<Connection>;
    uint64_t _conn_id;
    int _sockfd;
    EventLoop *_loop;
    Socket _socket;
    Channel _channel;
    Buffer _in_buffer;  // 输入缓冲区
    Buffer _out_buffer; // 输出缓冲区
    Any _context;
    Connstatu _statu;
    bool _enable_inactive_release;
    using ConnectedCallback = std::function<void(const PtrConnection &)>;
    using MessageCallback = std::function<void(const PtrConnection &, Buffer *)>;
    using ClosedCallback = std::function<void(const PtrConnection &)>;
    using AnyEventCallback = std::function<void(const PtrConnection &)>;
    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    ClosedCallback _server_closed_callback;
    AnyEventCallback _event_callback;

五、成员函数

构造

刚开始的状态一定要是半链接状态,只有在完成设置之后才是链接状态

cpp 复制代码
  Connection(EventLoop *loop, uint64_t conn_id, int sockfd)
        : _conn_id(conn_id), _sockfd(sockfd), _enable_inactive_release(false), _loop(loop), _statu(CONNECTING),
          _socket(_sockfd), _channel(loop, _sockfd)
    {
        _channel.SetCloseCallback(std::bind(&Connection::HandleClose, this));
        _channel.SetEventCallback(std::bind(&Connection::HandleEvent, this));
        _channel.SetReadCallback(std::bind(&Connection::HandleRead, this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite, this));
    }

状态设置

cpp 复制代码
typedef enum
{
    DISCONECTED,  // 链接关闭状态
    CONNECTING,   // 链接建立成功 - 待处理状态
    CONNECTED,    // 链接建立完成,各种设置已完成,可以通信的状态
    DISCONNECTING // 代关闭状态
} Connstatu;

链接可读事件回调

这里的ShutdownInLoop并不是真正的关闭,只是提供一个接口,可能有数据待发送,shared_from_this从对象自身获取智能指针,必须要继承

public std::enable_shared_from_this<Connection>才能使用

cpp 复制代码
void HandleRead()
    {
        char buf[65536];
        ssize_t ret = _socket.NonBlockRecv(buf, 65535);
        if (ret < 0)
        {
            return ShutdownInLoop();
        }
        _in_buffer.WriteAndPush(buf, ret);
        if (_in_buffer.ReadAblesize() > 0)
        {
            return _message_callback(shared_from_this(), &_in_buffer);
        }
        return;
    }

链接可写事件回调

这里的ReleaseInLoop就是真正的关闭接口,如果当前是带关闭状态,则有数据,发送完数据释放链接,没有数据则直接释放

cpp 复制代码
 void HandleWrite()
    {
        ssize_t ret = _socket.NonBlockSend(_out_buffer.ReadPosition(), _out_buffer.ReadAblesize());
        if (ret < 0)
        {
            if (_in_buffer.ReadAblesize() > 0)
            {

                _message_callback(shared_from_this(), &_in_buffer);
                return ReleaseInLoop();
            }
        }
        _out_buffer.MoveReadoffset(ret);
        if (_out_buffer.ReadAblesize() == 0)
        {
            _channel.DisableWrite();
            if (_statu == DISCONNECTING)
            {
                return ReleaseInLoop();
            }
        }
        return;
    }

链接关闭事件回调

一旦链接挂断了,套接字就什么都干不了,因此有数据待处理就处理以下,完毕关闭链接

cpp 复制代码
void HandleClose()
    {
        if (_in_buffer.ReadAblesize() > 0)
        {
            _message_callback(shared_from_this(), &_in_buffer);
        }
        return ReleaseInLoop();
    }

链接错误事件回调

cpp 复制代码
void HandleError()
    {
        return HandleClose();
    }

链接任意事件回调

1、刷新活跃度 2、调用组件使用者的任意事件回调

cpp 复制代码
void HandleEvent()
    {
        if (_enable_inactive_release == true)
        {
            _loop->TimerRefresh(_conn_id);
        }
        if (_event_callback)
        {
            _event_callback(shared_from_this());
        }
    }

链接获取之后,所处的状态下要进行各种设置(设置都监控,调用回调函数)

1、修改链接状态 2、启动读事件监控 3、调用回调函数

注意:当前状态的上层一定是半链接状态(链接并没有完全设置完毕),这个函数会启动读事件监控,一旦启动就能立即触发读事件,如果这个时候启动非活跃链接销毁,刷新活跃度的执行等任务,如果放在构造函数,这个时候没有定时任务,所以启动读事件必须要放到设置活跃链接是否销毁之后

cpp 复制代码
 void EstablishedInLoop()
    {
        assert(_statu == CONNECTING);
        _statu = CONNECTED;
        _channel.EnableRead();
        if (_connected_callback)
        {
            _connected_callback(shared_from_this());
        }
    }

启动活跃链接定时销毁

如果当前定时销毁任务已经存在,那就刷新延迟一下,如果没有设置

取消非活跃链接定时销毁

设置标志位,调用取消函数

释放链接

1、修改链接状态 2、移除链接事件监控 3、关闭描述符 4、如果有定时器队列中还有定时销毁任务,则取消任务

避免先移除服务器管理的链接信息导致Connection被释放,再去处理会出错,因此先调用用户的回调函数

关闭操作

这个关闭操作并不是真正的链接释放操作,需要判断有没有数据待处理,待发送

发送数据

切换协议

设置回调函数

一下接口都涉及链接操作所以要再loop内操作,所以都要放入队列中

获取数据接口

全部代码

cpp 复制代码
class Connection : public std::enable_shared_from_this<Connection>
{
private:
    using PtrConnection = std::shared_ptr<Connection>;
    uint64_t _conn_id;
    int _sockfd;
    EventLoop *_loop;
    Socket _socket;
    Channel _channel;
    Buffer _in_buffer;  // 输入缓冲区
    Buffer _out_buffer; // 输出缓冲区
    Any _context;
    Connstatu _statu;
    bool _enable_inactive_release;
    using ConnectedCallback = std::function<void(const PtrConnection &)>;
    using MessageCallback = std::function<void(const PtrConnection &, Buffer *)>;
    using ClosedCallback = std::function<void(const PtrConnection &)>;
    using AnyEventCallback = std::function<void(const PtrConnection &)>;
    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    ClosedCallback _server_closed_callback;
    AnyEventCallback _event_callback;
    void HandleRead()
    {
        char buf[65536];
        ssize_t ret = _socket.NonBlockRecv(buf, 65535);
        if (ret < 0)
        {
            return ShutdownInLoop();
        }
        _in_buffer.WriteAndPush(buf, ret);
        if (_in_buffer.ReadAblesize() > 0)
        {
            return _message_callback(shared_from_this(), &_in_buffer);
        }
        return;
    }
    void HandleWrite()
    {
        ssize_t ret = _socket.NonBlockSend(_out_buffer.ReadPosition(), _out_buffer.ReadAblesize());
        if (ret < 0)
        {
            if (_in_buffer.ReadAblesize() > 0)
            {

                _message_callback(shared_from_this(), &_in_buffer);
                return ReleaseInLoop();
            }
        }
        _out_buffer.MoveReadoffset(ret);
        if (_out_buffer.ReadAblesize() == 0)
        {
            _channel.DisableWrite();
            if (_statu == DISCONNECTING)
            {
                return ReleaseInLoop();
            }
        }
        return;
    }
    void HandleClose()
    {
        if (_in_buffer.ReadAblesize() > 0)
        {
            _message_callback(shared_from_this(), &_in_buffer);
        }
        return ReleaseInLoop();
    }

    void HandleError()
    {
        return HandleClose();
    }
    void HandleEvent()
    {
        if (_enable_inactive_release == true)
        {
            _loop->TimerRefresh(_conn_id);
        }
        if (_event_callback)
        {
            _event_callback(shared_from_this());
        }
    }
    void EstablishedInLoop()
    {
        assert(_statu == CONNECTING);
        _statu = CONNECTED;
        _channel.EnableRead();
        if (_connected_callback)
        {
            _connected_callback(shared_from_this());
        }
    }
    void ReleaseInLoop()
    {
        _statu = DISCONECTED;
        _channel.Remove();
        _socket.Close();
        if (_loop->HasTimer(_conn_id))
            CancelInactiveReleaseInLoop();

        if (_closed_callback)
            _closed_callback(shared_from_this());
        if (_server_closed_callback)
            _server_closed_callback(shared_from_this());
    }
    void SendInLoop(Buffer &buf)
    {
        if (_statu == DISCONECTED)
            return;
        _out_buffer.WriteBufferAndPush(buf);
        if (_channel.WriteAble() == false)
        {
            _channel.EnableWrite();
        }
    }
    void ShutdownInLoop()
    {
        _statu = DISCONNECTING;
        if (_in_buffer.ReadAblesize() > 0)
        {
            if (_message_callback)
            {
                _message_callback(shared_from_this(), &_in_buffer);
            }
        }
        if (_out_buffer.ReadAblesize() > 0)
        {
            if (_channel.WriteAble() == false)
            {
                _channel.EnableWrite();
            }
        }
        if (_out_buffer.ReadAblesize() == 0)
        {
            Release();
        }
    }
    void EnableInactiveReleaseInLoop(int sec)
    {
        _enable_inactive_release = true;
        if (_loop->HasTimer(_conn_id))
        {
            return _loop->TimerRefresh(_conn_id);
        }
        _loop->TimerAdd(_conn_id, sec, std::bind(&Connection::ReleaseInLoop, this));
    }
    void CancelInactiveReleaseInLoop()
    {
        _enable_inactive_release = false;
        if (_loop->HasTimer(_conn_id))
        {
            _loop->TimerCancel(_conn_id);
        }
    }
    void UpgradeInLoop(const Any &context, const ConnectedCallback &con, const MessageCallback &msg, const ClosedCallback &close, AnyEventCallback &event)
    {
        _context = context;
        _connected_callback = con;
        _message_callback = msg;
        _closed_callback = close;
        _event_callback = event;
    }

public:
    Connection(EventLoop *loop, uint64_t conn_id, int sockfd)
        : _conn_id(conn_id), _sockfd(sockfd), _enable_inactive_release(false), _loop(loop), _statu(CONNECTING),
          _socket(_sockfd), _channel(loop, _sockfd)
    {
        _channel.SetCloseCallback(std::bind(&Connection::HandleClose, this));
        _channel.SetEventCallback(std::bind(&Connection::HandleEvent, this));
        _channel.SetReadCallback(std::bind(&Connection::HandleRead, this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite, this));
    }
    ~Connection()
    {
        DBG_LOG("RELEASE CONNECTION : %p", this);
    }
    int Fd()
    {
        return _sockfd;
    }
    uint64_t Id()
    {
        return _conn_id;
    }
    Connstatu statu()
    {
        return _statu;
    }
    bool Connected()
    {
        return (_statu == CONNECTED);
    }
    Any *GetContext()
    {
        return &_context;
    }
    void SetConnectedCallback(const ConnectedCallback &cd)
    {
        _connected_callback = cd;
    }
    void SetClosedCallback(const ClosedCallback &cd)
    {
        _closed_callback = cd;
    }
    void SetMessageCallback(const MessageCallback &cd)
    {
        _message_callback = cd;
    }
    void SetAnyEventCallback(const AnyEventCallback &cd)
    {
        _event_callback = cd;
    }
    void SetSrvCloseCallback(const ClosedCallback &cd)
    {
        _server_closed_callback = cd;
    }
    void SetContext(Any context)
    {
        _context = context;
    }
    void Established()
    {
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop, this));
    }
    void Send(const char *data, size_t len)
    {
        Buffer buf;
        buf.WriteAndPush(data, len);
        _loop->RunInLoop(std::bind(&Connection::SendInLoop, this, std::move(buf)));
    }
    void Shutdown()
    {
        _loop->RunInLoop(std::bind(&Connection::ShutdownInLoop, this));
    }
    void Release()
    {
        _loop->QueueInLoop(std::bind(&Connection::ReleaseInLoop, this));
    }
    void EnableInactiveRelease(int sec)
    {
        _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop, this, sec));
    }
    void CancelInactiveRelease()
    {
        _loop->RunInLoop(std::bind(&Connection::CancelInactiveReleaseInLoop, this));
    }
    void Upgrade(const Any &context, const ConnectedCallback &con, const MessageCallback &msg, const ClosedCallback &close, AnyEventCallback &event)
    {
        _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop, this, context, con, msg, close, event));
    }
};
相关推荐
狐571 小时前
2026-03-15-因服务器网络访问问题从 GitHub 平滑迁移至 Gitee 等国内平台的方法
服务器·gitee·github
荆楚闲人1 小时前
ubuntu启动时无登录框无法进入系统的急救方法
linux·服务器·ubuntu
带娃的IT创业者7 小时前
Python 异步编程完全指南:从入门到精通
服务器·开发语言·python·最佳实践·asyncio·异步编程
一只鹿鹿鹿10 小时前
信息安全等级保护安全建设防护解决方案(总体资料)
运维·开发语言·数据库·面试·职场和发展
房产中介行业研习社10 小时前
2026年3月哪些房源管理系统功能全
大数据·运维·人工智能
biubiubiu070611 小时前
Linux / Ubuntu systemd 服务使用说明
linux·运维·ubuntu
MaximusCoder11 小时前
等保测评命令——Anolis Linux
linux·运维·服务器·网络·经验分享·安全·php
田里的水稻12 小时前
ubuntu22.04_构建openclaw开发框架
运维·人工智能·python
线束线缆组件品替网12 小时前
Adam Tech NPC-6-007-BU网线组件详解
服务器·网络·数码相机·智能路由器·电脑·51单片机·电视盒子