1. 简介
网络连接代理,用于处理网络连接,收发数据包。
2. 类与接口
CProxyConn使用需要配合两个辅助类CHandlerMap和CProxyTask。
CHandlerMap用于将数据包commandId和相应处理函数形成映射,方便通过commandId找到相应的执行函数。
CProxyTask任务代理,可以将工作任务封装成该类扔进工作队列,等待工作线程处理。
CProxyConn
// 处理网络连接
void OnConnect(net_handle_t handle)
// 由于数据包是在另一个线程处理的,所以不能在主线程delete数据包,所以需要Override这个方法
// 接收网络数据,接收完数据后将有效数据包里对应操作封装成任务交给其他工作线程处理
void OnRead()
// 定时器处理函数,用于定时发送数据包
void OnTimer(uint64_t curr_tick)
// 根据数据包中对应的业务操作封装成相应任务交给其他工作线程处理
void HandlePduBuf(uchar_t* pdu_buf, uint32_t pdu_len)
// 将待回复的数据包加入链表,等待其他工作线程发送
void AddResponsePdu(uint32_t conn_uuid, CImPdu* pPdu)
// 将主线程待回复数据包链表里内容发走,若消息包里pPdu为空则关闭连接
void SendResponsePduList()
// 关闭连接并释放资源
void Close()
// 定时器回调函数,处理每个连接的定时任务
void proxy_timer_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam)
// loop回调函数,将主线程待回复数据包链表里内容发走
void proxy_loop_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam)
/*
* 用于优雅的关闭连接:
* 服务器收到SIGTERM信号后,发送CImPduStopReceivePacket数据包给每个连接,
* 通知消息服务器不要往自己发送数据包请求,
* 然后注册4s后调用的回调函数,回调时再退出进程
*/
void exit_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam)
// 自定义SIGTERM处理事件
static void sig_handler(int sig_no)
// 创建线程池,添加loog任务,自定义SIGTERM事件,添加定时器任务
int init_proxy_conn(uint32_t thread_num)
3. 作为服务器一般流程
首先创建工作线程池,工作线程会不断从m_task_list里去除任务执行;创建工作线程池同时主线程会netlib_add_loop添加loop任务,不断将待回复数据包链表里内容发走;创建工作线程池同时主线程也会注册定时任务,定时任务主要用于服务器向客户端发送心跳包,同时关闭掉长时间未向服务器发送数据的客户端连接;之后开时监听客户端连接,新连接调用_AcceptNewSocket,之后该连接收到数据时CBaseSocket调用m_callback,这个m_callback为netlib_listen时设置的回调函数,CProxyConn::OnConnect会重置m_callback为imconn_callback,之后都是通过imconn_callback来管理;服务器会将客户端请求的业务操作封装成CProxyTask添加到m_worker_list,线程池里工作线程会处理m_worker_list里业务,这里业务操作和请求数据包里commandId通过CHandlerMap是一一映射的,可以快速的通过commandId执行相应的业务操作;业务操作会调用AddResponsePdu将服务器待回复数据包加入消息链表s_response_pdu_list,主线程loop函数proxy_loop_callback会将该链表中待回复消息全部发走。
4. 测试
//
// test_proxyconn.cpp
// test_proxyconn
//
// Created by blueBling on 22-04-29.
// Copyright (c) 2022年blueBling. All rights reserved.
//
#include "ProxyConn.h"
#include <iostream>
using std::cout;
using std::endl;
// this callback will be replaced by imconn_callback() in OnConnect()
void proxy_serv_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam)
{
if (msg == NETLIB_MSG_CONNECT)
{
CProxyConn* pConn = new CProxyConn();
pConn->OnConnect(handle);
}
else
{
log("!!!error msg: %d", msg);
}
}
int test_proxyconn() {
init_proxy_conn(3);
netlib_listen("192.168.49.128", 7777, proxy_serv_callback, NULL);
netlib_eventloop(10);
return 0;
}
int main(){
test_proxyconn();
//这里mysql和redis连接池未释放存在内存泄漏问题,解决方法参考test_dbpool
return 0;
}
测试结果: