找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 28069|回复: 25

mdk开源服务器引擎(更新V1.67 2013.10.29)+群号

[复制链接]
发表于 2012-11-7 16:55:52 | 显示全部楼层 |阅读模式
本帖最后由 serverdev2012 于 2013-10-29 16:31 编辑


  • 起因
    我这个人有一个不好的习惯——作为一个Coder就是不喜欢读代码
    在我的意识里,一个好的代码库应该是足够稳定的,稳定到不需要使用者为了解决问题而去读里面的代码。
    当然出于学习等目的,读代码是不可避免的
    所以我总希望能有一个轻量,轻量,再轻量的开发库就好了,于是萌生了开发一个微量级服务器引擎的想法,
    于是mdk(Micro-Development-Kit)微量级开发工具包,就是这套框加的名字
  • mdk做了什么事情
    服务器程序员开发最关心的其实只有3件事情,新连接到达,数据到达,连接断开。
    mdk就是基于以上3个主要业务,为服务器设计了OnConnect() OnMsg() OnClose()3个主要回调方法,用户的主要的工作就是实现这3个方法,所以我将这种开发模式命名为面向业务的开发。

    用户不再关心底层各种繁杂的处理,比如线程模型,各种同步,内部对象生命周期,各种缓冲只要专心写业务就好
    整个框架代码大约5000行,希望不会给大家造成阅读负担,
    希望这款服务器能给大家带来更多便利。
  • 项目相关url
    下载地址(使用github下载):https://github.com/huoyu820125/Micro-Development-Kit
    为方便没有github的朋友,从V1.25版本开始,新增google下载地址:http://code.google.com/p/micro-development-kit/
    文档地址(wiki):https://github.com/huoyu820125/Micro-Development-Kit/wiki
    OSChina博客:http://my.oschina.net/u/732357/blog
    脑图(.mm文件):使用freemind_1.0.0软件打开

  • 开发环境
    windows下,使用速度最快的经典VC++6.0,追求速度的朋友有服了
    经查VC6编译器优化后的代码存在bug,请大家使用更高版本的编译器,具使用者反映,目前VS2008 2010均可正常,2003 2005未收到反馈
    具体问题可以入群下载mdk VC6崩溃原因说明.rar
    linux下直接makefile编译
  • 更新历史

    V1.67(2013.10.29)
    1.服务器框架改动
      1.1增加表示连接数据的基础类HostData
            用户直接从HostData派生自己的数据类型即可
            通过NetHost::SetData()接口将数据与连接关联
            具体使用方法参考头文件
      1.2NetHost的IO接口优化
            数据长度,从原来的unsigned short扩大到unsigned int
            

    2.优化Logger日志类
      2.1增加3个接口
            SetMaxLogSize()日志最多保存这个大小的内容
            SetMaxExistDay()日志最多存在这么多天
            SetLogName()日至名字,会产生一个日志名的文件夹
      2.1写各种类型日志接口,统一为2个
            Info()输出日志
            StreamInfo()输出流

    3.扩展ConfigFile配置文件类
      增加对Section的支持
      使用范例
            配置文件内容
            [ser config]
            ip = 192.168.0.1
            port = 8888
            [/ser config]

            ConfigFile cfg( "./test.cfg" );
            string ip = cfg["ser config"]["ip"];
            cfg["ser config"]["ip"] = "127.0.0.1";
            cfg["ser config"]["port"] = 8080;//可以直接使用char*、string、int、float等进行赋值
            cfg.save();

    4.ThreadPool线程池增加1个接口,GetTaskCount取得当前任务数


    5.Socket类
      5.1优化Connect()接口,可以直接传递域名进行连接
      5.2增加static接口HostName2IP(),将域名转换成IP


    6.mapi.h增加几个公用api
      6.1mdk_assert代替assert()
      6.2GetFileSize
      6.3GetCUPNumber
      6.4CurThreadId
      6.5mdk_Date

    7.优化一些造成编译警告的代码


    V1.6.5(2013.07.05)

    解决windows下服务器退出时,IOCP阻塞问题,实现IOCPMonitor虚函数,解决

    bool IOCPMonitor::Stop()
    {
    #ifdef WIN32
    memset( &m_stopOverlapped.m_overlapped, 0, sizeof(OVERLAPPED) );
    m_stopOverlapped.m_wsaBuffer.buf = NULL;
    m_stopOverlapped.m_wsaBuffer.len = 0;
    m_stopOverlapped.m_overlapped.Internal = 0;
    m_stopOverlapped.sock = 0;
    m_stopOverlapped.completiontype = IOCPMonitor::close;

    ::PostQueuedCompletionStatus(m_hCompletPort, 0, 0, (OVERLAPPED*)&m_stopOverlapped );
    #endif
    return true;

    }


    V1.6.4(2013.05.08)解决在onconnect中主动close时崩溃问题
    1.NetEngine::ConnectWorker  感谢群友明亮发现此问题
    pConnect->Release();//使用完毕释放共享对象
    移动到最后return之前,否则如果在onconnect里面关闭连接,在MonitorConnect之前
    对象有可能被删除,MonitorConnect访问null指针

    2.NetEngine::ConnectWorker
    MonitorConnect之前加上条件true == pConnect->m_bConnect
    避免在onconnect里面关闭连接后,还将连接加入监听,触发多余的OnMsg

    3.threadpool::Stop 没有清空m_tasks

    4.threadpool::Stop 总是等到3秒超时才关闭

    5.NetEngine::Main里面sleep,使用信号代替,在stop时可以立刻停止线程
    提高stop响应速度

    6.NetHost::operator=
    AtomAdd(&obj.m_pConnect->m_useCount, 1);
    语句增加条件检查if ( NULL != obj.m_pConnect )
    以支持像下面这样主动释放对象
    nethost nullobj;
    host = nullobj;//主动释放host




    V1.6.2(2013.03.26)解决gcc4.7.2 4.7.3缺少头文件问题
    1.Socket.h加上linux头文件 include<unistd.h>  感谢群友YOKO提供头文件包含需求
    2.IOCP初始化有1处遗忘初始化,该漏洞暂未引发bug,CreateIoCompletionPort的最后1个参数忘记初始化,cpu数量,目前为自动获取机器cpu数量,感谢群友明亮提出


    V1.61(2013.03.01) 优化Stop操作
    1.WSAStartup与WSACleanup的调用从Start与Stop里面移出,到构造函数与析构函数
    2.m_pConnectPoll的释放,从stop里面移到析构中
    3.调整NetServer::Stop线程的停止顺序,将m_mainThread线程的停止提前到NetEngine::Stop()之前


    V1.60(2013.02.22) 健壮性强化
    1.ConfigFile 配置项未初始化,导致IsNull()方法不能返回正确结果
    2.NetEngine::Start()强化内部检查


    V1.59(2013.02.01)
    1.完善Socket::Send(),处理缓冲满时返回实际发送0byte(感谢明亮提出)
    2.完善Thread::Stop(),将线程句柄=NULL,只针对windows,以免析构函数再次Stop()(感谢董文嘉提出)
    3.mdk引擎发现连接产生时,将socket设置为非阻塞模式,指针windows,以免send操作阻塞
    4.mdk停止时主线程停止超时时间是3毫秒,修正为3000

    V1.58(2013.01.24)
    1.linux下使用Connect()接口产生的Socket未设置成非阻塞,导致epoll线程被recv方法阻塞,无法接收数据,已修正(感谢北极星同学测试发现此bug)

    2.windows下 Signal类析构时没有CloseHandle()(感谢明亮同学发现此问题)
    3.NetServer::main()注释修改为后台业务线程
    4.STNetServer::main()注释修改为后台业务线程


    V1.56(2013.01.14)
    修正1对n lock free队列bug
    bug位置 Queue.cpp
    1.
        /*
            只有在NPush并发情况下,因Push无序完成,第一个位置的Push未完成,
            后面的Push就先完成提示有数据,导致这里检查第一个位置时,发现没有数据可读
            因为该类只允许1对N,必然是单线程Pop(),所以条件内m_pop不需要并发控制
         */

        if ( m_queue[popPos].IsEmpty )
        {
            m_pop--;
            AtomAdd(&m_nReadAbleCount,1);
            return NULL; //忘记这一句return NULL,对引擎的影响:无,因为只有在 1pop对n push情况下才会进入此分支,而引擎只使用了1 push对n pop的模式
        }

    2.Push() Pop()以上检查条件中m_nWriteAbleCount m_nReadAbleCount的增加没有使用原子操作做并发控制,实际应该要原子操作。对引擎的影响:linux版本有可能造成遗漏通知,win版未使用Queue类

    3.相应的休整了以上条件的注释,更容易理解一点


    V1.55(2013.01.12)
    1.53心跳检查条件没有bug,因调试时连接的lib版本问题,误认为是bug
    修正回来,1.54版本废除


    V1.54(2013.01.11)
    1.心跳代码检查优化出一个bug,修正


    V1.53(2013.01.11)
    1.ConfigFile类,增加IsNull方法,检查一个配置值是否被配置
    2.Logger类删除构造函数中多余的参数
    3.mdk网络引擎自动重连的定时器代码优化
    4.NetHost::ID() NetConnect=NULL访问空指针,该问题只有用户自己创建NetHost对象时,才会出现,因为用户创建时是没有做初始化的。
    引擎的OnXXX()返回给的NetHost对象,ID()是保证有效的


    V1.52(2013.01.05)
    1.优化内存池性能,初始化时减小分组大小,使遍历次数减少,感谢北极星提供的性能检测数据
    2.删除NetHost::GetLength()方法,对用户无用,且容易误导用户
    3.相应的修改文档,example


    V1.51(2012.12.27)
    1.优化不同2个不同连接,一个连接断开,另外一个连接进入的时序
    将NetEngine::CloseConnect()中的pConnect->GetSocket()->Close()调用
    推迟到CloseWorker()中,在m_pNetServer->OnCloseConnect()之后执行

            A.首先推迟Close的目的
                在OnCloseConnect()完成前,也就是业务层完成连接断开业务前
                不让系统回收socket的句柄,再利用
                
                以避免发生如下情况。
                    比如用户在业务层(NetServer派生类)中创建map<int,NetHost>类型host列表
                    在NetServer::OnConnect()时加入
                    在NetServer::OnClose())时删除

                    如果在这里就执行关闭socket(假设句柄为100)

                    业务层NetServer::OnClose将在之后得到通知,
                    如果这时又有新连接进来,则系统会从新使用100作为句柄分配给新连接。
                    由于是多线程并发,所以可能在NetServer::OnClose之前,先执行NetServer::OnConnect()
                    由于NetServer::OnClose还没有完成,100这个key依旧存在于用户创建的map中,
                    导致NetServer::OnConnect()中的插入操作失败
                   
              因此,用户需要准备一个wait_insert列队,在OnConnect()中insert失败时,
              需要将对象保存到wait_insert列队,并终止OnConnect()业务逻辑

              在OnClose中删除对象后,用对象的key到wait_insert列队中检查,
              找到匹配的对象再insert,然后继续执行OnConnect的后续业务,
              OnConnect业务逻辑才算完成
             
              1.代码上非常麻烦
              2.破坏了功能内聚,OnConnect()与OnClose()逻辑被迫耦合在一起

            B.再分析推迟Close有没有其它副作用
            问题1:由于连接没有关闭,在server端主动close时,连接状态实际还是正常的,
            如果client不停地发送数据,会不会导致OnMsg线程一直接收不完数据,
            让OnClose没机会执行?
            
              答:不会,因为m_bConnect标志被设置为false了,而OnMsg是在MsgWorker()中被循环调用,
            每次循环都会检查m_bConnect标志,所以即使还有数据可接收,OnMsg也会被终止


    V1.50(2012.12.26)
    1.解决gcc4.4.6编译问题,原因1.32版中新增的ShareMemory类用到memcpy系列字符串api,在gcc4.4.6下找不到头文件
    2.整理example代码,删除无用代码


    V1.35(2012.12.24)
    1.解决Bug 连接断开后,自动重连没有效果
    2.NetServer STNetServer类补上重连定时设置接口
    3.ConfigFile类写入顺序与读入顺序保持一至


    V1.34 (2012.12.14)
    主要是为了方便windows下VS系列使用者编译,做了相关目录的修正      
          包含头文件修正为相对路径,
    编译mdk lib库不再需要在VC下再设置头文件搜索目录但其它项目使用mdk.lib依旧需要设置mdk头文件目录,
    或包含时指定目录



    V1.33(2012.12.12)
    加强ConfigFile功能
    直接存取int char short int32 float double等基本类型



    V1.32 (2012.12.10)
    1.将代码中实现的通用api整理到一起mapi.*
    2.补正VC工程,新增单线程版代码没有编译进lib
    3.相应更新文档
    4.增加工具类共享内存ShareMemory.*
    5.配置文件类ConfigFile.*更加傻瓜式,析构时自动保存修改


    V1.30 (2012.12.04)
    1.主要是为实现nosql需要单线程的io模型,于是新增一个单线程模型服务器引擎匡架的
       基类为STNetServer与NetServer接口完全一样
       事件响应返回host类型为STNetHost,与NetHost接口完全一样
    2. 1.25之后小更新
         1.修正了Socket::Accept在windows下的失败bug
         2.发送部分io吞吐能力忘记跟随recv一起扩大,不扩大也没关系,就是原来的低吞吐,已扩大


    V1.25 (2012.11.30)
    主要优化了io吞吐能力
    1.每次io吞吐量从256byte提升至8k,就是IOBufferBlock.h中的宏#define BUFBLOCK_SIZE 8192,BUFBLOCK_SIZE是一块连续内存的最大尺寸,所以一次recv最大可接收的数据受此宏定义限制。

    可根据需求自行修改,注意BUFBLOCK_SIZE很大时,请适当调小IOBufferBlock::ms_pMemoryPool初始化内存数量,目前是10000块,也就是8万k大小的内存池
    2.linux下每次io从4k提升至1M
    3.NetEngine::HeartMonitor()小优化


    V1.24 (2012.11.29)     
    首先最近几次更新,要感谢来至OSChina.net的Fenlog积极提出的相关意见
    1.删除被注释掉的无用代码(所谓的僵尸代码)
    2.消除class NetServer内存泄露,~NetServer()时没有释放NetEngine对象
        还有一个地方的内存没有释放,就是以下红色的全局变量,而且是private的,程序退出就会释放没有关系的,如果实在不爽,可以自行修改为public或增加static释放方法,在程序退出的地方,主动释放一下
    class IOBufferBlock
    {
            friend class IOBuffer;
    //////////////////////////////////////////////////////////////////////////
    //使用自己的内存管理
    private:
            //内存池,在这里为该类型的对象分配内存
            static MemoryPool* ms_pMemoryPool;
            //内存池线程安全锁
            static Mutex* ms_pPoolMutex;




    V1.23 (2012.11.21更新)

    修正了接收数据的一切边界情况
    1.nethost::recv第2个参数传递0
        具体现象:由于没有读取数据,缓冲状态一直为可读,导致不停的触发OnMsg,修正后如果recv传递0则返回false,且不再触发onmsg,除非有新数据到达修正:IOBuffer::ReadData(),第一行参数检查,0 > uLength 修正为0 >= uLength,读取0长度也返回不可读
    2.nethost::recv刚好将缓冲中数据全部读出
        具体现象:iobuffer中已经没有数据可读,但onmsg会再被触发1次,数据长度为0修正:NetConnect::IsReadAble()方法,状态为可读时,多检查一下iobuffer的长度,如果<=0则返回不可读

    V1.22r (2012.11.21更新)

    修正Bug:VC编译Release版本启动崩溃
           Bug原因是Executor类中调用函数指针的汇编代码在release下不能正确定位函数地址,导致访问非法地址
          修正后所有需要经过Executor远程调用的类成员函数(例如传递给Thread.Run(),ThreadPool::Accept(),Task::Accept()的成员函数),需将函数的调用规则申明为RemoteCall
          如:void* RemoteCall Fun(void*)


    V1.21  (2012.11.08更新)

    框架优化1处,接口增加2个
    1.对于框架的优化,保证OnConnect OnMsg OnClose完全序列化,这要感谢野火与Connor提出的宝贵建议

    2.NetHost增加GetAddress和GetServerAddress方法
    用于得连接双方IP 端口信息




    V1.20  便利性的优化

    1.修正1.10版本中编译Signal.cpp时,include atom.h文件名大小写不可识别问题

    2.优化服务器引擎NetHost的使用删除了Hold()Free()方法,取而代之的是复制构造函数,=运算符,析构函数来自动化管理引用计数,
    用起来更加方便,让用户完全不用关心对象使用中的生命周期问题


    3.优化服务器网络事件通知顺序1.10版本中同一个连接上OnConnect与OnMsg是无序并发的优化后在同一个连接上,确保了OnConnect完成之前,不会有该连接的OnMsg发生

    4.相应的修正example与文档

    5.mdk类库,增加智能指针类SharedPtr

    6.mdk类库,Thread在windows下stop时没有CloseHandle()。(前几天群里看到讨论CloseHandle()问题,帮我发现到一个不足点,于是补上呵呵)

    V1.10  github上发布以来第一个大版本

    1.各方面已经调整稳定,为将来写wiki有针对性,设置一个大版本

    2.增加了服务器引擎接口文档.docx,方便喜欢看文档的朋友

    3.修正NetServer.h NetHost.h方法注释,与增加了服务器引擎接口文档.docx完全一样,方便喜欢直接看代码的朋友

    4.修正NetHost关于Group的方法为线程安全的

    5.修正心跳检查机制默认为不检查,与NetServer::SetHeartTime()的注释匹配,以免用户被注释误导
最后水平有限,希望大家多提意见,如果发现什么bug或有什么问题,欢迎指出,我一定尽快答复
我的QQ49038554
QQ群号245934320




发表于 2012-11-8 10:11:43 | 显示全部楼层
不错,支持楼主的精神

点评

谢谢支持,有什么问题,可以直接问我  详情 回复 发表于 2012-11-8 18:24
 楼主| 发表于 2012-11-8 18:24:31 | 显示全部楼层
djoin 发表于 2012-11-8 10:11
不错,支持楼主的精神

谢谢支持,有什么问题,可以直接问我
发表于 2012-11-17 15:34:26 | 显示全部楼层
支持开源,支持楼主!
发表于 2012-11-18 14:26:52 | 显示全部楼层
to serverdev2012:
    请放个下载的链接吧,许多人都不熟悉git, 我下了个git windows客户端,注册了个账户,但在客户端上登录就报密码错误,可能是注册时用的是XP IE8, git不支持IE8. 请直接放个链接或放在google上。 谢谢!

点评

兄弟,google我弄好了 下载地址:http://code.google.com/p/micro-development-kit/ 有什么问题,可以问我  详情 回复 发表于 2012-11-30 15:20
兄弟,谢谢你的建议,我也感觉github太麻烦,不过这几天我尝试了很多次,google一直上不去,可能最近18大的关系 你可以加我Q49038554,我直接发你一份, 等google好了,我再传一份  详情 回复 发表于 2012-11-19 09:20
 楼主| 发表于 2012-11-19 09:20:55 | 显示全部楼层
eGoldenBright 发表于 2012-11-18 14:26
to serverdev2012:
    请放个下载的链接吧,许多人都不熟悉git, 我下了个git windows客户端,注册了个账户 ...

兄弟,谢谢你的建议,我也感觉github太麻烦,不过这几天我尝试了很多次,google一直上不去,可能最近18大的关系

你可以加我Q49038554,我直接发你一份,
等google好了,我再传一份
 楼主| 发表于 2012-11-30 15:20:29 | 显示全部楼层
eGoldenBright 发表于 2012-11-18 14:26
to serverdev2012:
    请放个下载的链接吧,许多人都不熟悉git, 我下了个git windows客户端,注册了个账户 ...

兄弟,google我弄好了
下载地址:http://code.google.com/p/micro-development-kit/
有什么问题,可以问我
发表于 2012-12-1 12:22:23 | 显示全部楼层
都是服务器端的代码,能不能搞个好用点的客户端用的SOCKET库

点评

mdk服务器引擎本身是一个server-client的一体化的通信引擎,没有client与server区别 你可以直接在client里面用 client server其实是一个相对概念,如果你的程序去连接别人,那么你是client别人是server 现在很多通  详情 回复 发表于 2012-12-1 15:55
 楼主| 发表于 2012-12-1 15:54:33 | 显示全部楼层
mdk服务器引擎本身是一个server-client的一体化的通信引擎,没有client与server区别
你可以直接在client里面用

client server其实是一个相对概念,如果你的程序去连接别人,那么你是client别人是server
现在很多通信程序其实已经不再是一个单纯的client或server,
很多时候在connect别人的服务同时,可能自身也扮演一个服务的角色会接受其它连接

connect()去连接服务端,用listen()去接受某个端口上的连接

如果你client只需要连接服务器,不需要对外提供服务,可以不用listen()

io work线程数量也可以根据需要设置,如果不接受连接,建议设置成1
 楼主| 发表于 2012-12-1 15:55:17 | 显示全部楼层
hopping 发表于 2012-12-1 12:22
都是服务器端的代码,能不能搞个好用点的客户端用的SOCKET库

mdk服务器引擎本身是一个server-client的一体化的通信引擎,没有client与server区别
你可以直接在client里面用

client server其实是一个相对概念,如果你的程序去连接别人,那么你是client别人是server
现在很多通信程序其实已经不再是一个单纯的client或server,
很多时候在connect别人的服务同时,可能自身也扮演一个服务的角色会接受其它连接

connect()去连接服务端,用listen()去接受某个端口上的连接

如果你client只需要连接服务器,不需要对外提供服务,可以不用listen()

io work线程数量也可以根据需要设置,如果不接受连接,建议设置成1
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-11-21 17:00 , Processed in 0.030149 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表