目录
一、目的
对链接进行全方位的管理,对通信链接的所有操作都是通过这个模块提供的功能实现的
二、功能设计
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));
}
};