/** * Tencent is pleased to support the open source community by making MSEC available. * * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the GNU General Public License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may * obtain a copy of the License at * * https://opensource.org/licenses/GPL-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ /** * @filename mt_api.h * @info 微线程封装系统api, 同步调用微线程API,实现异步调度 */ #ifndef __MT_API_H__ #define __MT_API_H__ #include #include using std::vector; namespace NS_MICRO_THREAD { /******************************************************************************/ /* 微线程用户接口定义: UDP短连接收发接口 */ /******************************************************************************/ /** * @brief 采用随机端口的socket收发接口, 由socket来决定上下文, 业务来保证上下文 * [注意] UDP发送buff, 不推荐static变量, 有一定风险导致上下文错乱[重要] * @param dst -请求发送的目的地址 * @param pkg -请求包封装的包体 * @param len -请求包封装的包体长度 * @param rcv_buf -接收应答包的buff * @param buf_size -modify-接收应答包的buff大小, 成功返回时, 修改为应答包长度 * @param timeout -超时时间, 单位ms * @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败, 可打印errno */ int mt_udpsendrcv(struct sockaddr_in* dst, void* pkg, int len, void* rcv_buf, int& buf_size, int timeout); /******************************************************************************/ /* 微线程用户接口定义: TCP连接池收发接口 */ /******************************************************************************/ /** * @brief TCP检测报文是否接收完整的回调函数定义 * @param buf 报文保存缓冲区 * @param len 已经接收的长度 * @return >0 实际的报文长度; 0 还需要等待接收; <0 报文异常 */ typedef int (*MtFuncTcpMsgLen)(void* buf, int len); /** * @brief TCP会采用连接池的方式复用IP/PORT连接, 连接保持默认10分钟 * [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要] * @param dst -请求发送的目的地址 * @param pkg -请求包封装的包体 * @param len -请求包封装的包体长度 * @param rcv_buf -接收应答包的buff * @param buf_size -modify-接收应答包的buff大小, 成功返回时, 修改为应答包长度 * @param timeout -超时时间, 单位ms * @param check_func -检测报文是否成功到达函数 * @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败, * -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接,-10 参数无效 */ int mt_tcpsendrcv(struct sockaddr_in* dst, void* pkg, int len, void* rcv_buf, int& buf_size, int timeout, MtFuncTcpMsgLen chek_func); enum MT_TCP_CONN_TYPE { MT_TCP_SHORT = 1, /// 短连接 MT_TCP_LONG = 2, /// 长连接 MT_TCP_SHORT_SNDONLY = 3, /// 短连接只发 MT_TCP_LONG_SNDONLY = 4, /// 长连接只发 MT_TCP_BUTT }; /** * @brief TCP收发接口,可以选择后端保持连接或者短连接 * [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要] * @param dst -请求发送的目的地址 * @param pkg -请求包封装的包体 * @param len -请求包封装的包体长度 * @param rcv_buf -接收应答包的buff,只发不收可以设置为NULL * @param buf_size -modify-接收应答包的buff大小, 成功返回时, 修改为应答包长度,只发不收,设置为NULL * @param timeout -超时时间, 单位ms * @param check_func -检测报文是否成功到达函数 * @param type - 连接类型 * MT_TCP_SHORT: 一收一发短连接; * MT_TCP_LONG : 一发一收长连接; * MT_TCP_LONG_SNDONLY : 只发不收长连接; * MT_TCP_SHORT_SNDONLY: 只发不收短连接; * @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败, * -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接, -10 参数无效 */ int mt_tcpsendrcv_ex(struct sockaddr_in* dst, void* pkg, int len, void* rcv_buf, int* buf_size, int timeout, MtFuncTcpMsgLen func, MT_TCP_CONN_TYPE type = MT_TCP_LONG); /** * @brief TCP检测报文是否接收完整的回调函数 * @param buf 报文保存缓冲区 * @param len 已经接收的长度 * @param closed 远端关闭连接,兼容通过链接关闭来确定报文长度的业务 * @param msg_ctx 解析报文的上下文变量。通过该值,业务可以实现报文解析状态机等,避免重复检查 * 业务在mt_tcpsendrcv中传入该参数,框架回调时传递给业务。该变量可以为类或者结构体,业务自定义。 * 报文解析结果,保存在变量中,mt_tcpsendrcv返回后,直接使用 * 【注意】 该回调函数传入的buf指针可能变化,所以报文解析状态机相关位置信息请使用偏移量 * @param msg_len_detected 传出参数 如果业务确定了报文长度,则将其设置为true,否则为false。传入时为false。 * 【注意】如果该值返回true,框架以函数返回值作为报文长度(>0)持续收包,在收包完成前,不再调用该MtFuncTcpMsgChecker函数;报文接收完成后,调用MtFuncTcpMsgChecker函数检查一次报文。减少因零碎收包引起的无效调用。 * @return >0 建议的接收缓冲大小; 0 还需要等待接收; <0 报文异常 * 【注意】 * 以下两种情况可以返回大于0: * 1,业务确定报文长度,返回报文长度 * 2,业务不确定报文长度,给出接收buf的建议长度,如果长度大于现有buf长度,框架根据该值realloc buf。 * * 返回值为0,表示业务无法确定报文长度,需要接续接收。如果buf收满,框架将realloc buf,buf大小扩大一倍 * 返回值小于0,表示业务确定报文错误 */ typedef int (*MtFuncTcpMsgChecker)(void* buf, int len, bool closed, void* msg_ctx, bool &msg_len_detected); /** * @brief TCP收发接口,可以选择后端保持连接或者短连接 * [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要] * @param dst -请求发送的目的地址 * @param pkg -请求包封装的包体 * @param len -请求包封装的包体长度 * @param rcv_buf -【传出参数】,参考参数 keep_rcv_buf。业务不需要malloc该内存。void* rcv_buf=NULL: 传给框架即可 * @param recv_pkg_size -接收应答包的buff的初始大小。函数返回0时,返回报文实际长度。 * @param timeout -超时时间, 单位ms * @param check_func -检测报文是否成功到达函数 * @param msg_ctx -解析报文的上下文变量。 * * @param type - 连接类型 * MT_TCP_SHORT: 一收一发短连接; * MT_TCP_LONG : 一发一收长连接; * MT_TCP_LONG_SNDONLY : 只发不收长连接; * MT_TCP_SHORT_SNDONLY: 只发不收短连接; * @param keep_rcv_buf -true,调用成功后,框架将最后的rcv_buf赋值给传出参数,业务负责释放该buf。否则框架在调用结束前释放该buf。【注意】 * 业务需要自己在msg_ctx中保留相关信息。【框架通过malloc申请内存】 默认框架自动释放该buf,业务需要在ctx保存信息 * @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败, * -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接, -10 参数无效, -11,申请接收buf失败 */ int mt_tcpsendrcv_ex(struct sockaddr_in* dst, void* pkg, int len, void*& rcv_buf, int& recv_pkg_size, int timeout, MtFuncTcpMsgChecker check_func, void* msg_ctx=NULL, MT_TCP_CONN_TYPE type = MT_TCP_LONG, bool keep_rcv_buf=false); /** * @brief TCP会采用连接池的方式复用IP/PORT连接, 连接保持默认10分钟 * [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要] * @param dst -请求发送的目的地址 * @param pkg -请求包封装的包体 * @param len -请求包封装的包体长度 * @param rcv_buf -【传出参数】,参考参数 keep_rcv_buf。 * @param recv_pkg_size -接收应答包的buff的初始大小。函数返回0时,返回报文实际长度。 * @param timeout -超时时间, 单位ms * @param check_func -检测报文是否成功到达函数 * @param msg_ctx -解析报文的上下文变量。 * @param keep_rcv_buf -true,框架将最后的rcv_buf赋值给传出参数,业务负责释放该buf。否则框架在调用结束前释放该buf。【注意】 * 业务需要自己在msg_ctx中保留相关信息。【框架通过malloc申请内存】 * @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败, * -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接, -10 参数无效 */ int mt_tcpsendrcv(struct sockaddr_in* dst, void* pkg, int len, void*& rcv_buf, int& recv_pkg_size, int timeout, MtFuncTcpMsgChecker check_func, void* msg_ctx=NULL, bool keep_rcv_buf=false); /******************************************************************************/ /* 微线程用户接口定义: 微线程Task多路并发模型接口定义 */ /******************************************************************************/ /** * @brief 微线程子任务对象定义 */ class IMtTask { public: /** * @brief 微线程任务类的处理流程入口函数 * @return 0 -成功, < 0 失败 */ virtual int Process() { return -1; }; /** * @brief 设置task执行结果 * @info 即Process返回值 */ void SetResult(int rc) { _result = rc; } /** * @brief 获取task执行结果 * @info 即Process返回值 */ int GetResult(void) { return _result; } /** * @brief 设置task类型 */ void SetTaskType(int type) { _type = type; } /** * @brief 获取task类型 * @info 如果业务有多种task,可以使用该字段区分不同的task类型 * @return 获取task类型 */ int GetTaskType(void) { return _type; } /** * @brief 微线程任务基类构造与析构 */ IMtTask() {}; virtual ~IMtTask() {}; protected: int _type; // task类型,多种类型task,业务可以自定义类型,方便从基类转换 int _result; // task执行结果,即Process返回值 }; typedef vector IMtTaskList; /** * @brief 多路IO并发, Task-fork-wait模式接口 * @param req_list -task list 封装独立api的task列表 * @return 0 成功, -1 创建子线程失败 */ int mt_exec_all_task(IMtTaskList& req_list); /******************************************************************************/ /* 微线程用户接口定义: 微线程封装系统接口 */ /******************************************************************************/ /** * @brief 微线程主动sleep接口, 单位ms * @info 业务需要主动让出CPU时使用 */ void mt_sleep(int ms); /** * @brief 微线程获取系统时间,单位ms */ unsigned long long mt_time_ms(void); /******************************************************************************/ /* 微线程用户接口定义: 微线程用户私有数据接口 */ /******************************************************************************/ /** * @brief 设置当前IMtMsg的私有变量 * @info 只保存指针,内存需要业务分配 */ void mt_set_msg_private(void *data); /** * @brief 获取当前IMtMsg的私有变量 * @return 私有变量指针 */ void* mt_get_msg_private(); /******************************************************************************/ /* 微线程用户接口定义: 微线程封装系统接口(不推荐使用) */ /******************************************************************************/ /** * @brief 微线程框架初始化 * @info 业务不使用spp,裸用微线程,需要调用该函数初始化框架; * 使用spp,直接调用SyncFrame的框架初始化函数即可 * @return false:初始化失败 true:初始化成功 */ bool mt_init_frame(int argc=0, char * const argv[]=NULL); /** * @brief 设置微线程独立栈空间大小 * @info 非必须设置,默认大小为128K */ void mt_set_stack_size(unsigned int bytes); /** * @brief 微线程包裹的系统IO函数 recvfrom * @param fd 系统socket信息 * @param buf 接收消息缓冲区指针 * @param len 接收消息缓冲区长度 * @param from 来源地址的指针 * @param fromlen 来源地址的结构长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功接收长度, <0 失败 */ int mt_recvfrom(int fd, void *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, int timeout); /** * @brief 微线程包裹的系统IO函数 sendto * @param fd 系统socket信息 * @param msg 待发送的消息指针 * @param len 待发送的消息长度 * @param to 目的地址的指针 * @param tolen 目的地址的结构长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功发送长度, <0 失败 */ int mt_sendto(int fd, const void *msg, int len, int flags, const struct sockaddr *to, int tolen, int timeout); /** * @brief 微线程包裹的系统IO函数 connect * @param fd 系统socket信息 * @param addr 指定server的目的地址 * @param addrlen 地址的长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功发送长度, <0 失败 */ int mt_connect(int fd, const struct sockaddr *addr, int addrlen, int timeout); /** * @brief 微线程包裹的系统IO函数 accept * @param fd 监听套接字 * @param addr 客户端地址 * @param addrlen 地址的长度 * @param timeout 最长等待时间, 毫秒 * @return >=0 accept的socket描述符, <0 失败 */ int mt_accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int timeout); /** * @brief 微线程包裹的系统IO函数 read * @param fd 系统socket信息 * @param buf 接收消息缓冲区指针 * @param nbyte 接收消息缓冲区长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功接收长度, <0 失败 */ ssize_t mt_read(int fd, void *buf, size_t nbyte, int timeout); /** * @brief 微线程包裹的系统IO函数 write * @param fd 系统socket信息 * @param buf 待发送的消息指针 * @param nbyte 待发送的消息长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功发送长度, <0 失败 */ ssize_t mt_write(int fd, const void *buf, size_t nbyte, int timeout); /** * @brief 微线程包裹的系统IO函数 recv * @param fd 系统socket信息 * @param buf 接收消息缓冲区指针 * @param len 接收消息缓冲区长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功接收长度, <0 失败 */ ssize_t mt_recv(int fd, void *buf, int len, int flags, int timeout); /** * @brief 微线程包裹的系统IO函数 send * @param fd 系统socket信息 * @param buf 待发送的消息指针 * @param nbyte 待发送的消息长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功发送长度, <0 失败 */ ssize_t mt_send(int fd, const void *buf, size_t nbyte, int flags, int timeout); /** * @brief 微线程等待epoll事件的包裹函数 * @param fd 系统socket信息 * @param events 等待的事件 IN/OUT * @param timeout 最长等待时间, 毫秒 * @return >0 到达的事件, <0 失败 */ int mt_wait_events(int fd, int events, int timeout); void* mt_start_thread(void* entry, void* args); } #endif