mynet开源库

news2024/11/25 7:10:32
1.介绍

个人实现的c++开源网络库.

2.软件架构

1.结构图
在这里插入图片描述
2.基于event的自动分发机制
在这里插入图片描述
3.多优先级分发队列,延迟分发队列
在这里插入图片描述
内部event服务于通知机制的优先级为0,外部event优先级为1
当集中处理分发的event_callback时,若激活了更高优先级的event_callback,可在当前event_callback回调处理结束.进入下次时间循环,以便高优先级event_callback及时得到处理.

4.主动分发event_callback来向工作线程提交回调任务
在这里插入图片描述
5.通信对象的高效缓存区管理
5.1.以携带管理信息的可变尺寸块作为基础缓存单位
在这里插入图片描述
5.2.以可变尺寸块的链式队列构成的缓存区
在这里插入图片描述
5.3.块的可复用
对由于消耗而需释放的块,采用缓存而非释放来管理.
在这里插入图片描述
释放块时候,依据块容量,释放到缓存指定容量下块的容器.
需要新块时,依据所需容量,先从缓存取块,取不到时,再动态分配新的块.

5.4.连接对象的连接管理
采用一个互斥锁,实现连接对象上连接建立过程,连接断开过程至多只有一个并发.
a. 连接过程
在这里插入图片描述
b.断开过程
在这里插入图片描述
c.断开投递快速响应
设置手动分发event_callback的优先级为0,借助event_callback的多优先级分发队列.可使得当前event_callback回调处理结束,即可开始下轮循环,从而快速处理分发的高优先级的event_callback

5.5.连接对象高效锁管理
a. 通过连接锁实现连接建立,连接断开的串行化.
b. 可读事件处理,收包回调无锁处理.
因为可读事件及收包回调只在单个工作线程引发,且通过连接建立,连接断开的串行化处理.收包过程及其回调可以实现为无锁的.
c. 通过发送锁实现发送缓存区并发管理
用户线程执行发送,工作线程可写事件执行异步发送分别充当了发送缓存的生产者,消费者.我们用发送互斥锁进行并发管理.

5.6.高效的io复用
a. 采用epoll作为io复用器,其比select,poll在管理大规模事件监控时性能更优异.
b. 只在必要时注册连接对象可写eventevent_base
b.1. 连接建立过程,我们将其注册到event_base,以便实现连接结果异步处理.
b.2. 用户线程向发送缓存写入新数据时,我们将其注册到event_base以便实现数据在可写事件中的异步发送.
b.3. 在异步发送里,判断发送缓存为空时,自动移除可写event.以便减少不必要的事件分发.

5.7.简单易用
a. 以c++实现.
b. 以工厂模式管理资源.
c. 接口定义清晰,详见使用说明.

系统要求

1.支持c++11
2.支持cmake
3.linux系统

安装教程

1.在mynet/build下执行:cmake ../
2.在mynet/build下执行:make
3.在mynet/build/demo下执行:./srv_test开启服务端
4.在mynet/build/demo下执行:./cli_test开启客户端

使用说明

1.客户端demo

#include "ifactory.h"
#include "ilog.h"
#include "iclient.h"
#include "define.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <thread>  
#include <chrono>
#include <mutex> 
#include <iostream>  
#include <fstream>
#include <endian.h>

std::mutex mtx;  
std::ofstream logFile("cli_logfile.txt", std::ios_base::out);  
void logcb(mynet::LOGLEVEL nLevel, const char *msg){
    //if(nLevel == mynet::LOGLEVEL::EVENT_LOG_ERR){
        pthread_t thread_id = pthread_self(); 
        std::lock_guard<std::mutex> lock(mtx);  
        logFile << "tid:" << (uint32_t)thread_id << " level: " << (int32_t)nLevel << ": msg: " << msg << std::endl; 
    //}
}

struct Msg1{
    int32_t nLen;
    int32_t nType;
    int32_t nMsg1;
    char strName[100];
    Msg1(){
        nLen = CalculateSize();
        nType = 1;
    }
    static int32_t CalculateSize(){
        return 112;
    }
    void Serialize(char* lpOut){
        int32_t nTmpLen = htobe32(nLen);
        memcpy(lpOut, (char*)&nTmpLen, 4);
        int32_t nTmpType = htobe32(nType);
        memcpy(lpOut+4, (char*)&nTmpType, 4);
        
        int32_t nMsg = htobe32(nMsg1);
        memcpy(lpOut+8, (char*)&nMsg, 4);
        memcpy(lpOut+12, strName, 100);
    }
    Msg1* DeSerialize(char* lpIn){
        Msg1* lpM = new Msg1();
        int32_t nTmpLen = *(int32_t*)lpIn;
        lpM->nLen = be32toh(nTmpLen);
        int32_t nTmpType = *(int32_t*)((char*)lpIn+4);
        lpM->nType = be32toh(nTmpType);

        int32_t nMsg = *(int32_t*)(lpIn+8);
        lpM->nMsg1 = be32toh(nMsg);
        memcpy(lpM->strName, lpIn+12, 100);
        return lpM;
    }
};
struct Msg2{
    int32_t nLen;
    int32_t nType;
    int32_t nMsg2;
    char strName1[100];
    char strName2[100];
    Msg2(){
        nLen = CalculateSize();
        nType = 2;
    }
    static int32_t CalculateSize(){
        return 212;
    }
    void Serialize(char* lpOut){
        int32_t nTmpLen = htobe32(nLen);
        memcpy(lpOut, (char*)&nTmpLen, 4);
        int32_t nTmpType = htobe32(nType);
        memcpy(lpOut+4, (char*)&nTmpType, 4);

        int32_t nMsg = htobe32(nMsg2);
        memcpy(lpOut+8, (char*)&nMsg, 4);
        memcpy(lpOut+12, strName1, 100);
        memcpy(lpOut+112, strName2, 100);
    }
    Msg2* DeSerialize(char* lpIn){
        Msg2* lpM = new Msg2();
        int32_t nTmpLen = *(int32_t*)lpIn;
        lpM->nLen = be32toh(nTmpLen);
        int32_t nTmpType = *(int32_t*)(lpIn+4);
        lpM->nType = be32toh(nTmpType);

        int32_t nMsg = *(int32_t*)(lpIn+8);
        lpM->nMsg2 = be32toh(nMsg);
        memcpy(lpM->strName1, lpIn+12, 100);
        memcpy(lpM->strName2, lpIn+112, 100);
        return lpM;
    }
};
class ClientCallback:public mynet::IClientCallback{
public:
    virtual ~ClientCallback(){
        printf("~ClientCallback\n");
    }
    virtual void OnEvent(short events){
        printf("recv event %d\n", events);
    }
    virtual void OnMessage(char* lpMsg, int32_t nLen){
        printf("msg len:%d\n", nLen);
    }
};
int main(){
    mynet::SetLogCb(logcb);
    mynet::FactoryConfig stConfig;
    stConfig.nWorkThreadNum = 1;
    mynet::IFactory* lpFac = mynet::CreateFactory(stConfig);
    lpFac->Start();
    mynet::ClientConfig stCliConfig;
    stCliConfig.nConnTimeout = 4;
    stCliConfig.nPort = 13142;
    strcpy(stCliConfig.strIp, "127.0.0.1");
    stCliConfig.nThreadIndex = 0;

    ClientCallback stCall;
    mynet::IClient* lpCli = lpFac->CreateClient(stCliConfig, &stCall);
    int32_t nRet = lpCli->DoConnect(13142, stCliConfig.strIp, 4, true, true);
    printf("conn ret %d\n", nRet);
    if(nRet != RET_CODE_CONN_SUCC){
        return 0;
    }

    char* lpBuf = (char*)malloc(Msg1::CalculateSize());
    for(int32_t i = 0; i < 10; i++){
        Msg1 stM1;
        stM1.nMsg1 = 11;
        strcpy(stM1.strName, "StrName1"); 
        stM1.Serialize(lpBuf);
        int32_t nSend = lpCli->SendData(lpBuf, Msg1::CalculateSize());
        printf("%d send ret %d\n", i, nSend);
    }

    std::this_thread::sleep_for(std::chrono::seconds(6)); 
    lpCli->DoDisconnect(true, true);
    lpFac->Stop();
    mynet::DestroyFactory(lpFac);
    return 0;
}

2.服务端demo

#include "ifactory.h"
#include "ilog.h"
#include "iserver.h"
#include "define.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <thread>  
#include <chrono>
#include <mutex> 
#include <iostream>  
#include <fstream>
std::mutex mtx;  
std::ofstream logFile("svr_logfile.txt", std::ios_base::out);  
void logcb(mynet::LOGLEVEL nLevel, const char *msg){
    //if(nLevel == mynet::LOGLEVEL::EVENT_LOG_ERR){
    	pthread_t thread_id = pthread_self(); 
        std::lock_guard<std::mutex> lock(mtx);  
        logFile << "tid:" << (uint32_t)thread_id << " level: " << (int32_t)nLevel << ": msg: " << msg << std::endl; 
    //}
}

struct Msg1{
    int32_t nLen;
    int32_t nType;
    int32_t nMsg1;
    char strName[100];
    Msg1(){
        nLen = CalculateSize();
        nType = 1;
    }
    static int32_t CalculateSize(){
        return 112;
    }
    void Serialize(char* lpOut){
        int32_t nTmpLen = htobe32(nLen);
        memcpy(lpOut, (char*)&nTmpLen, 4);
        int32_t nTmpType = htobe32(nType);
        memcpy(lpOut+4, (char*)&nTmpType, 4);
        
        int32_t nMsg = htobe32(nMsg1);
        memcpy(lpOut+8, (char*)&nMsg, 4);
        memcpy(lpOut+12, strName, 100);
    }
    Msg1* DeSerialize(char* lpIn){
        Msg1* lpM = new Msg1();
        int32_t nTmpLen = *(int32_t*)lpIn;
        lpM->nLen = be32toh(nTmpLen);
        int32_t nTmpType = *(int32_t*)((char*)lpIn+4);
        lpM->nType = be32toh(nTmpType);

        int32_t nMsg = *(int32_t*)(lpIn+8);
        lpM->nMsg1 = be32toh(nMsg);
        memcpy(lpM->strName, lpIn+12, 100);
        return lpM;
    }
};
struct Msg2{
    int32_t nLen;
    int32_t nType;
    int32_t nMsg2;
    char strName1[100];
    char strName2[100];
    static int32_t CalculateSize(){
        return 212;
    }
    void Serialize(char* lpOut){
        int32_t nTmpLen = htobe32(nLen);
        memcpy(lpOut, (char*)&nTmpLen, 4);
        int32_t nTmpType = htobe32(nType);
        memcpy(lpOut+4, (char*)&nTmpType, 4);

        int32_t nMsg = htobe32(nMsg2);
        memcpy(lpOut+8, (char*)&nMsg, 4);
        memcpy(lpOut+12, strName1, 100);
        memcpy(lpOut+112, strName2, 100);
    }
    Msg2* DeSerialize(char* lpIn){
        Msg2* lpM = new Msg2();
        int32_t nTmpLen = *(int32_t*)lpIn;
        lpM->nLen = be32toh(nTmpLen);
        int32_t nTmpType = *(int32_t*)(lpIn+4);
        lpM->nType = be32toh(nTmpType);

        int32_t nMsg = *(int32_t*)(lpIn+8);
        lpM->nMsg2 = be32toh(nMsg);
        memcpy(lpM->strName1, lpIn+12, 100);
        memcpy(lpM->strName2, lpIn+112, 100);
        return lpM;
    }
};

class ServerCallback:public mynet::IServerCallback{
public:
    ServerCallback(){
    }
    virtual ~ServerCallback(){
        printf("~ServerCallback\n");
    }
    virtual void OnEvent(int32_t nIndex, short events){
        printf("index_%d,events_%d\n", nIndex, events);
    }
    virtual void OnMessage(int32_t nIndex, char* lpMsg, int32_t nLen){
        printf("index_%d,len_%d\n", nIndex, nLen);
        m_lpSvr->SendData(nIndex, lpMsg, nLen);
    }
public:
    mynet::IServer* m_lpSvr = nullptr;
};

int main(){
    mynet::SetLogCb(logcb);
    mynet::FactoryConfig stConfig;
    stConfig.nWorkThreadNum = 1;
    mynet::IFactory* lpFac = mynet::CreateFactory(stConfig);
    lpFac->Start();
   
    mynet::ServerConfig stSvrConfig;
    stSvrConfig.nPort = 13142;
    stSvrConfig.nListenThreadIndex = 0;
    
    ServerCallback stSvrCallback;
    mynet::IServer* lpSvr = lpFac->CreateServer(stSvrConfig, &stSvrCallback);
    stSvrCallback.m_lpSvr = lpSvr;
    lpSvr->Start();
    
    while(true){
        std::this_thread::sleep_for(std::chrono::seconds(6)); 
    }
    lpSvr->Stop();
    lpFac->Stop();
    mynet::DestroyFactory(lpFac);
    return 0;
}
后续待处理事项

1.完善各类场景单元测试
2.支持epollet模式事件分发
3.制作规范清晰的使用文档

开源地址

1.https://github.com/xubenhao/mynet
2. https://gitee.com/xubenhao2/mynet

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1579006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙ArkUI声明式学习:【UI资源管理】

OpenHarmony 应用的资源分类和资源的访问以及应用开发使用的像素单位以及各单位之间相互转换的方法。 资源分类 移动端应用开发常用到的资源比如图片&#xff0c;音视频&#xff0c;字符串等都有固定的存放目录&#xff0c;OpenHarmony 把这些应用的资源文件统一放在 resourc…

线程的666种状态

文章目录 在Java中&#xff0c;线程有以下六种状态&#xff1a; NEW&#xff1a;新建状态&#xff0c;表示线程对象已经被创建但还未启动。RUNNABLE&#xff1a;可运行状态&#xff0c;表示线程处于就绪状态&#xff0c;等待系统分配CPU资源执行。BLOCKED&#xff1a;阻塞状态…

Centos Docker Oracle11g 密码过期修改

症状&#xff1a; Centos Oracle11g环境变量配置 如果没有配置环境变量&#xff0c;需要先配置Oracle环境变量&#xff0c;否则执行sqlplus时会提示&#xff1a;SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory 配置方法&#xff1a; 第一步&a…

《系统架构设计师教程(第2版)》第8章-系统质量属性与架构评估-03-ATAM方法架构评估实践(下)

文章目录 3. 测试阶段3.1 头脑风暴和优先场景&#xff08;第7步&#xff09;3.1.1 理论部分3.1.2 示例 3.2 分析架构方法&#xff08;第8步&#xff09;3.2.1 调查架构方法1&#xff09;安全性2&#xff09;性能 3.2.2 创建分析问题3.2.3 分析问题的答案胡佛架构银行体系结构 3…

初学ELK - elk部署

一、简介 ELK是3个开源软件组合&#xff0c;分别是 Elasticsearch &#xff0c;Logstash&#xff0c;Kibana Elasticsearch &#xff1a;是个开源分布式搜索引擎&#xff0c;提供搜集、分析、存储数据三大功能。它的特点有&#xff1a;分布式&#xff0c;零配置&#xff0c;自…

开源免费的多功能PDF工具箱

它支持修改PDF、编辑PDF书签、导出PDF书签、导入书签、生成、合并、拆分、提取页面内容、提取图片、OCR 功能介绍: 修改PDF信息&#xff1a;修改文档属性、页码编号、页面链接、页面尺寸&#xff1b;删除自动打开网页等动作&#xff0c;去除复制及打印限制&#xff1b;设置阅读…

ios swift5 “Sign in with Apple“(使用苹果登录)怎样接入(第三方登录)集成AppleID登录

文章目录 截图1.在开发者网站的app id中添加Sign in with Apple功能2.在Xcode中添加Sign in with Apple功能3.代码&#xff1a;只有第一次登录的时候可以获取到用户名参考博客chatGPT答案 截图 1.在开发者网站的app id中添加Sign in with Apple功能 1.1 如果你新建app id,记得在…

OpenHarmony实战:物联网解决方案之芯海cst85芯片移植案例

本文介绍基于芯海cst85芯片的cst85_wblink开发板移植OpenHarmony LiteOS-M轻量系统的移植案例。 开发了Wi-Fi连接样例和XTS测试样例&#xff0c;同时实现了wifi_lite, lwip, startup, utils, xts, hdf等部件基于OpenHarmony LiteOS-M内核的适配。 移植架构上采用Board和Soc分…

流式密集视频字幕

流式密集视频字幕 摘要1 IntroductionRelated Work3 Streaming Dense Video Captioning Streaming Dense Video Captioning 摘要 对于一个密集视频字幕生成模型&#xff0c;预测在视频中时间上定位的字幕&#xff0c;理想情况下应该能够处理长的输入视频&#xff0c;预测丰富、…

GEE:样本点的样式设置

作者:CSDN @ _养乐多_ 本文将介绍在Google Earth Engine (GEE)平台上为样本点设置样式的方法和代码,样本点可以设置成任何颜色,以及7种形状,以便更直观了解数据的分布和特征。 文章目录 一、统一设置样式1.1 示例代码1.2 示例代码链接二、每一类一个样式2.1 示例代码2.2…

React - 你使用过高阶组件吗

难度级别:初级及以上 提问概率:55% 高阶组件并不能单纯的说它是一个函数,或是一个组件,在React中,函数也可以做为一种组件。而高阶组件就是将一个组件做为入参,被传入一个函数或者组件中,经过一定的加工处理,最终再返回一个组件的组合…

【C语言】结构体、枚举、联合(自定义类型)

文章目录 前言一、结构体1.结构体的声明2.结构体的自引用3.结构体变量的定义和初始化4.结构体成员的访问5.结构体内存对齐&#xff08;重点&#xff09;6.#pragma修改默认对齐数7.结构体传参 二、位段1.位段的声明2.位段的内存分配3.位段的跨平台问题 三、枚举四、联合 &#x…

Vite+Vue3.0项目使用ant-design-vue <a-calendar>日期组件汉化

antd的弹框、日期等默认为英文&#xff0c;要把英文转为中文请看下文&#xff1a; 1.首先我们要在main.js中引入ant-design组件库并全局挂载&#xff1a; import App from ./App import Antd from ant-design-vue; import ant-design-vue/dist/antd.css;const app createApp(…

备考ICA----Istio实验18---单集群中部署多个Istio控制面

备考ICA----Istio实验18—单集群中部署多个Istio控制面 单个 Kubernetes 控制面以及多个 Istio 控制面和多个网格。通过 Kubernetes 命名空间和 RBAC 实现软多租户业务隔离。 1. 环境准备 1.1 创建2个命名空间 kubectl create ns usergroup-1 kubectl label ns usergroup-…

React - 你知道props和state之间深层次的区别吗

难度级别:初级及以上 提问概率:60% 如果把React组件看做一个函数的话,props更像是外部传入的参数,而state更像是函数内部定义的变量。那么他们还有哪些更深层次的区别呢,我们来看一下。 首先说props,他是组件外部传入的参数,我们知道…

如何使用vscode启动Flask并实现无公网IP远程访问内网服务

文章目录 1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 本篇文章主要讲解如何在本地安装Flask&#xff0c;以及如何将其web界面发布到公网进行远程访问。 Flask是目前十分流行的web框架&#xff0c;采用Python编程语…

蓝桥杯真题Day48 倒计时7天 练了几道真题小程序+回溯剪枝应用一个小程序

[蓝桥杯 2023 省 A] 更小的数 题目描述 小蓝有一个长度均为 n 且仅由数字字符 0∼9 组成的字符串&#xff0c;下标从0到 n−1&#xff0c;你可以将其视作是一个具有n位的十进制数字num&#xff0c;小蓝可以从num 中选出一段连续的子串并将子串进行反转&#xff0c;最多反转一次…

2月智能手表线上电商市场(京东天猫淘宝)分析:华为手表成最大赢家!

近年来&#xff0c;各大厂商纷纷积极布局健康管理领域&#xff0c;智能手表成为可穿戴市场的热门产品。随着越来越多的厂商进入&#xff0c;智能手表的芯片技术、显示屏技术、传感器技术等都在不断进步&#xff0c;整体性能和功能得到显著提升&#xff0c;使得用户体验更加出色…

Leetcode 6. Z 字形变换

将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING” 行数为 3 时&#xff0c;排列如下&#xff1a; P A H N A P L S I I G Y I R 之后&#xff0c;你的输出需要从左往右逐行读取&#xff0…

2024年MathorCup+认证杯数模竞赛助攻规划+竞赛基本信息介绍

为了更好的帮助大家助攻未来几天的竞赛&#xff0c;除了给大家上次提供的2024年上半年数学建模竞赛一览表&#xff08;附赠12场竞赛的优秀论文格式要求&#xff09; 又为大家提供了本周末两场数模竞赛2023年的竞赛题目以及优秀论文&#xff0c;希望能对大家本周末的竞赛有所帮…