mynet开源库

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 框架集成Knife4j

本次示例使用 Spring Boot 作为脚手架来快速集成 Knife4j,Spring Boot 版本2.3.5.RELEASE,Knife4j 版本2.0.7&#xff0c;完整代码可以去参考 knife4j-spring-boot-fast-demo pom.xml 完整文件代码如下 <?xml version"1.0" encoding"UTF-8"?> &l…

Terraform进阶技巧

Terraform 是管理 IaC 的强大工具&#xff0c;常用常新。在这一部分我们将探索 Terraform 的进阶技能&#xff0c;包括 Terraform 模块、远程状态存储、Terraform 工作区以及自定义 Provider。 1、Terraform 模块 Terraform 模块是可复用的 Terraform 代码包&#xff0c;其…

Scaffold-GS 代码阅读笔记

1. 系统启动部分 使用 python 中的 parser 库 为配置系统的参数设定, 和3DGS 类似&#xff0c;并且使用safe_state(args.quiet) 函数 为每一次的 log 输出加上对应的 时间戳 ## 配置参数的设定lp ModelParams(parser)op OptimizationParams(parser)pp PipelineParams(pars…

嵌入式linux系统链接腾讯云的方法

各位开发者大家好,今天主要给大家分享一个,如何使用linux系统链接腾讯云的方法,因为微信小程序越来越普遍,链接腾讯云也是日常必须掌握的一个技能。 第一:【实验目的】 1、linux 系统连接腾讯云的方法 第二:【实验原理】 涉及到原理图添加原理图 2、linux开发板 …

Windows:Redis数据库图形化中文工具软件——RESP(3)

这个是用于连接redis数据库的软件工具&#xff0c;安装在windows上的图形化界面&#xff0c;并且支持中文&#xff0c;是在github上的一个项目 1.获取安装包 发布 lework/RedisDesktopManager-Windows (github.com)https://github.com/lework/RedisDesktopManager-Windows/rel…

6.11物联网RK3399项目开发实录-驱动开发之定时器的使用(wulianjishu666)

嵌入式实战开发例程【珍贵收藏&#xff0c;开发必备】&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1tkDBNH9R3iAaHOG1Zj9q1Q?pwdt41u 定时器使用 前言 RK3399有 12 个 Timers (timer0-timer11)&#xff0c;有 12 个 Secure Timers(stimer0~stimer11) 和 2 个 …

学习JavaEE的日子 Day35 字节流

5.字节流 应用场景&#xff1a;操作二进制数据&#xff08;音频、视频、图片&#xff09; abstract class InputStream – 字节输入流的基类&#xff08;抽象类&#xff09; abstract class OutputStream – 字节输出流的基类&#xff08;抽象类&#xff09; class FileInputSt…

JVM 垃圾回收算法

JVM 垃圾回收算法 标记清除算法复制算法标记整理算法分代算法 标记清除算法 标记-清除&#xff08;Mark-Sweep&#xff09;算法属于早期的垃圾回收算法&#xff0c;它是由标记阶段和清除阶段构成的。标记阶段会给所有的存活对象做上标记&#xff0c;而清除阶段会把没有被标记的…

记录一次浅拷贝导致的缺陷

背景&#xff1a;假期表查询&#xff0c;表中存放的工作日信息是按照月份维度的&#xff0c;例如1月的假期表信息是NNNYYYYYNN.....一共31天&#xff0c;如果是工作日那么就是Y&#xff0c;如果非工作日那就是N。获取指定日期的下一个工作日&#xff0c;就会先查出这个月份的这…

史上首位阿贝尔奖、图灵奖双得主!2023图灵奖授予随机性大佬Avi Wigderson

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 这位多产的研究者发现了随机性和计算之间的深刻联系&#xff0c;其贡献影响了密码学、复杂性…

LLM激活稀疏性加速

相关工作 Deja vu Contextual sparsity for efficient llms at inference time LLM in a flash Efficient Large Language Model Inference with Limited Memory ReLU Strikes Back Exploiting Activation Sparsity in Large Language Models ReLU2 Wins: Discovering Effi…

家居网购项目(一)

文章目录 1.前置知识1.项目开发阶段2.Java经典三层架构3.项目具体分层&#xff08;包方案&#xff09;4.MVC 2.开发环境搭建1.新建普通javaweb项目&#xff0c;导入jar包2.创建项目结构3.搭建前端页面 3.会员注册前端js校验1.需求分析2.代码login.html 3.结果4.调试阶段1.验证信…

[目标检测] OCR: 文字检测、文字识别、text spotter

概述 OCR技术存在两个步骤&#xff1a;文字检测和文字识别&#xff0c;而end-to-end完成这两个步骤的方法就是text spotter。 文字检测数据集摘要 daaset语言体量特色MTWI中英文20k源于网络图像&#xff0c;主要由合成图像&#xff0c;产品描述&#xff0c;网络广告(淘宝)MS…

Linux下使用C语言实现高并发服务器

高并发服务器 这一个课程的笔记 相关文章 协议 Socket编程 高并发服务器实现 线程池 使用多进程并发服务器时要考虑以下几点&#xff1a; 父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)系统内创建进程个数(与内存大小相关)进程创建过多是否降低整体…

代码随想录训练营day36

第八章 贪心算法 part05 1.LeetCode. 无重叠区间 1.1题目链接&#xff1a;435. 无重叠区间 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;B站卡哥视频 1.2思路&#xff1a;我来按照右边界排序&#xff0c;从左向右记录非交叉区间的个数。最后用区间总数减去非交叉区…

yolov8训练自己数据集的一些小细节

例如我的路径格式如下: 这里要保证两个对齐, train/images/img1.jpg,2,3,xxx train/labels/img1.txt,2,3,xxx val/images/img1.jpg,2,3,xxx val/labels/img1.txt,2,3,xxxyaml文件读取路径的时候,个人猜测是依靠替换字符串找标签的, 因为yaml文件里没有指明如何加载labels,它后…

MobX原理剖析:基于可观察状态和自动依赖追踪的响应式状态管理

我们用代码示例来说明 MobX 的核心原理。 首先,我们定义一个简单的 Store 类,其中包含一个可观察的计数器状态: import { observable, action } from mobx;class CounterStore {observable count 0;actionincrement () > {this.count;};actiondecrement () > {this.…

【STM32G431RBTx】备战蓝桥杯嵌入式→省赛试题→第十四届

文章目录 前言一、题目二、模块初始化三、代码实现interrupt.h:interrupt.c:main.h:main.c: 四、完成效果五、总结 前言 无 一、题目 二、模块初始化 1.LCD这里不用配置&#xff0c;直接使用提供的资源包就行 2.KEY, 四个按键IO口都要配置&#xff0c;分别是PB0, PB1,PB2,PA…

【端云一体化开发】云函数本地运行/调试启动失败的两种解决方案

最近本地调试云函数一直出现这个错误&#xff1a;Before launch task execute failed! details:java.lang.lllegalStateException: npm installfailed 这个问题的原因似乎是运行云函数的时候会重新下载 npm 及相关依赖文件&#xff0c;但是 DevEco 的 npm 模块出错导致这个步骤…

软考121-上午题-【软件工程】-敏捷方法

一、敏捷方法 敏捷开发的总体目标是通过“尽可能早地、持续地对有价值的软件的交付”使客户满意。通过在软件开发过程中加入灵活性&#xff0c;敏捷方法使用户能够在开发周期的后期增加或改变需求。 敏捷过程的典型方法有很多&#xff0c;每一种方法基于一套原则&#xff0c;这…