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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter如何集成到已有iOS工程上

大家好&#xff0c;我是咕噜铁蛋&#xff0c;今天我将和大家分享一个实用的技术教程——如何将Flutter集成到已有的iOS工程中。Flutter是Google推出的一款开源的移动UI框架&#xff0c;它允许开发者使用Dart语言来开发高性能、美观的原生应用&#xff0c;并支持iOS和Android两大…

聚观早报 | 百度文心一言上线新功能;腾势Z9GT将发布

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月08日消息 百度文心一言上线新功能 腾势Z9GT将发布 华为将举办鸿蒙春季沟通会 苹果与Shutterstock达成协议 O…

LeetCode初级算法书Java题解日常更新

LeetCode初级算法高效题解&#xff08;含思路注释&#xff09; 文章目录 LeetCode初级算法高效题解&#xff08;含思路注释&#xff09;前言一、数组1.删除排序数组中的重复项2.买卖股票的最佳时机 II3.旋转数组4.存在重复元素 总结 前言 决定用四个月过一下算法 一、数组 1.…

threejs 组-层级模型 | 本地坐标和世界坐标 | 局部坐标系和世界坐标系 | 本地矩阵.materix和世界矩阵.matrixWorld

文章目录 组- THREE.Group递归遍历模型树结构object3D.traverse()object3D.add (object.Object3D..) 添加对象 和 object3D.remove(object.Object3D..) 移除对象 局部坐标系和世界坐标系辅助坐标器 AxesHelper 本地坐标和世界坐标 - 基于世界坐标系的位置本地坐标与世界坐标的理…

Redis7(二)数据类型及其用法

一、概述 命令不区分大小写&#xff0c;key区分大小写 数据类型针对value String List Set Hash ZSet bitmap GEO HyperLogLog Stream bitfield 二、String <K,V> 1、设值/取值 getrange key index1 index2 getrange key 0 -1//获取所有的值 SETRANGE KEY_N…

XC7A35T-2FGG484 嵌入式FPGA现场可编程门阵列 Xilinx

XC7A35T-2FGG484 是一款由Xilinx&#xff08;赛灵思&#xff09;制造的FPGA&#xff08;现场可编程门阵列&#xff09;芯片 以下是XC7A35T-2FGG484 的主要参数&#xff1a; 1. 系列&#xff1a;Artix-7 2. 逻辑单元数量&#xff1a;33280个 3. 工艺技术&#xff1a;28nm 4. …

Linux 5.10 Pstore 功能测试

目录 简介环境配置内核配置参考备注 简介 Pstore(Persistent store support)是用于系统发生oops或panic时&#xff0c;自动保存内核log buffer中的日志。随着功能不断完善&#xff0c;Duo S使用Linux 5.10已经支持保存console日志、ftrace消息和用户空间日志的收集&#xff0c…

STC89C52学习笔记(三)

STC89C52学习笔记&#xff08;三&#xff09; 综述&#xff1a;本文讲述了通过51单片机控制LED闪烁、流水灯、按键控制LED亮灭、按键控制LED实现二进制、按键控制LED左右移。 一、LED 1.LED闪烁 1&#xff09;LED电路原理 LED采用共阳极&#xff0c;当LED另一端为低电平时…

前端二维码工具小程序产品使用说明书

一、产品概述 前端二维码工具小程序是一款便捷实用的二维码生成与识别工具&#xff0c;通过本小程序&#xff0c;用户可以轻松根据文本或链接生成二维码&#xff0c;并支持扫一扫功能识别二维码内容&#xff0c;同时提供复制识别内容的功能。此外&#xff0c;本小程序还具备美…

登录信息失效后多次请求提示合并成一次

在通常的业务场景中经常会出现进入页面之后一次性发送好多个请求,如果登录信息失效,那就会出现很多提示 类似这种多个提示的,看起来不美观,希望改成可以把在短时间内出现相同的错误信息,只提示一次,其他的就不提示了 实现思路 通常业务中每一个请求的code都是有具体的意思,可以…

网络安全 | 什么是区块链?

关注WX&#xff1a;CodingTechWork 概述 定义 区块链是一个共享的、不可篡改的账本&#xff0c;旨在促进业务网络中的交易记录和资产跟踪流程。资产可以是有形的&#xff08;如房屋、汽车、现金、土地&#xff09;&#xff0c;也可以是无形的&#xff08;如知识产权、专利、…

【记录】LangChain|llama 2速通版

官方教程非常长&#xff0c;我看了很认可&#xff0c;但是看完了之后呢就需要一些整理得当的笔记让我自己能更快地找到需求。所以有了这篇文章。【写给自己看的&#xff0c;里面半句废话的解释都没有&#xff0c;如果看不懂的话直接看官方教程再看我的】 我是不打算一开始就用…

RabbitMQ基本使用及企业开发中注意事项

目录 一、基本使用 二、使用注意事项 1. 生产者重连机制 - 保证mq服务是通的 2. 生产者确认机制 - 回调机制 3. MQ的可靠性 4. Lazy Queue模式 5. 消费者确认机制 一、基本使用 部署完RabbitMQ有两种使用方式&#xff1a; 网页客户端Java代码 MQ组成部分&#xff1a;…

Verilog语法——按位取反“~“和位宽扩展的优先级

前言 先说结论&#xff0c;如下图所示&#xff0c;在Verilog中“~ ”按位取反的优先级是最高的&#xff0c;但是在等式计算时&#xff0c;有时候会遇到位宽扩展&#xff0c;此时需要注意的是位宽扩展的优先级高于“~”。 验证 仿真代码&#xff0c;下面代码验证的是“~”按位取…

ChernoCPP 2

视频链接&#xff1a;【62】【Cherno C】【中字】C的线程_哔哩哔哩_bilibili 参考文章&#xff1a;TheChernoCppTutorial_the cherno-CSDN博客 Cherno的C教学视频笔记&#xff08;已完结&#xff09; - 知乎 (zhihu.com) C 的线程 #include<iostream> #include<th…

【攻防世界】catcat-new

首先进入环境&#xff0c;这是一个介绍猫的网站&#xff1a; 网站的URL没有发现问题&#xff0c;使用dirsearch对网站进行扫描&#xff0c;看是否有可以访问的窗口&#xff1a; 发现 /admin 可以访问&#xff0c;我们尝试访问&#xff1a; /admin中没有flag。我们返回初始界面&…

Redis数据库的简介、部署及常用命令

关系数据库与非关系型数据 关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。sQL语句&#xff08;标准数据查询语言&#xff09;就是一种基于关系型数据库的语言&#xff0c…

LangChain - OpenGPTs

文章目录 MessageGraph 消息图认知架构AssistantsRAGChatBot 持久化配置新模型新工具astream_events总结 关键链接&#xff1a; OpenGPT GitHub 存储库YouTube 上的 OpenGPT 演练LangGraph&#xff1a;Python、JS 两个多月前&#xff0c;在 OpenAI 开发日之后&#xff0c;我们…

项目管理中的估算活动资源

在项目管理中&#xff0c;资源估算是一项至关重要的任务。正确地估算活动资源可以确保项目的顺利进行&#xff0c;避免资源浪费和不必要的延误。以下是对项目管理中常见的活动资源类型的详细分析。 一、人力资源 人力资源是项目管理中最基本的资源之一。它包括项目团队成员的…

Linux gcc day5粘滞位

粘滞位 背景&#xff1a;一定时在一个公共目录&#xff08;root创建&#xff09;下。进行临时文件的操作 Linux系统中有很多人&#xff0c;我们需要在一个公共目录下&#xff0c;进行临时文件的操作&#xff08;增删查改&#xff09; 创建一个根目录下的dir&#xff08;mytmp…