一个开源的服务器框架,特别适用于开发小游戏

开发 前端
一个跨平台的c++<->lua服务器快速解决方案,该框架即可快速响应服务器开发工作,设计思想:“让事情变得更简单”

 [[385982]]

jwEngine

一个跨平台的c++<->lua服务器快速解决方案,该框架即可快速响应服务器开发工作,设计思想:“让事情变得更简单”

网络底层采用libuv(node.js底层库),异步io助力使单线程也能释放澎湃动力,跨平台支持epoll、iocp、ipv6。框架支持tcp、udp/kcp、websocket、http,并保证了接口的一致性,使用了sol2将所有接口都导出到lua,可以选择用lua开发逻辑。

使用modern c++开发,尽可能的使用std::move、std::string_view减少内存复制。

该框架使用异步事件,不建议使用多线程,避免多线程上下文切换开销和破坏代码美感,网络部分和逻辑部分使用一个主事件循环驱动。建议的方案是多进程单线程的横向扩展,按照业务控制各个进程的粒度,当然mysql和redis可以加入到线程池中。

创建一个tcp服务器

只需要简单几行代码即可创建一个tcp高性能服务器,并自动处理数据包头和粘包(其中包头包含消息长度和协议号),构建一个完好的NetPacket交给你。

  1. class INetEvent : public NetEvent 
  2. public
  3.   virtual void onAccept(NetConnect * conn){} 
  4.   virtual void onClose(NetConnect * conn){} 
  5.   virtual void onMsg(NetConnect * conn, int msgtype, NetPacket * pack){} 
  6. }; 
  7.  
  8. int main() 
  9.   EventLoop::Instance()->init(); 
  10.  
  11.   INetEvent eve; 
  12.   NetServer server(EventLoop::Instance(), &eve); 
  13.   server.listen("127.0.0.1"3001); 
  14.  
  15.   return EventLoop::Instance()->run(); 

创建一个kcp服务器

c++的kcp服务器示例,快速构建你的帧同步服务器,保证消息的可靠性

  1. class KNetEvent : public KcpEvent 
  2. public
  3.   virtual void onAccept(KcpSession * conn){}; 
  4.   virtual void onClose(KcpSession * conn){}; 
  5.   virtual void onMsg(KcpSession * conn, int msgtype, UdpPacket * pack){} 
  6.   virtual void onUdpTimeout(KcpSession * s){} 
  7. }; 
  8.  
  9. int main() 
  10.   EventLoop::Instance()->init(); 
  11.  
  12.   KNetEvent eve; 
  13.   KcpServer server(EventLoop::Instance(), &eve); 
  14.   server.start("127.0.0.1"3001); 
  15.  
  16.   return EventLoop::Instance()->run(); 

创建一个websocket服务器

自动完成解析websocket协议工作

  1. class IWebEvent : public WebSocketEvent 
  2. public
  3.   virtual void onHandshake(WebSocketConnect * conn){}; 
  4.   virtual void onAccept(WebSocketConnect * conn){}; 
  5.   virtual void onClose(WebSocketConnect * conn){}; 
  6.   virtual void onMsg(WebSocketConnect * conn, WebSocketPacket * pack){}; 
  7. }; 
  8.  
  9. int main() 
  10.   EventLoop::Instance()->init(); 
  11.  
  12.   IWebEvent wevent; 
  13.   WebSocketServer server(EventLoop::Instance(), &wevent); 
  14.   server.listen("127.0.0.1"8080); 
  15.  
  16.   return EventLoop::Instance()->run(); 

创建一个http服务器

http仅支持简单的get post请求

  1. const char * html = R"(<html> 
  2. <body> 
  3. <h1>login</h1> 
  4. <p>hello world!</p> 
  5.   <form action="login" method="post"
  6.     <input type="text" name="user"/> 
  7.     <input type="password" name="pass"/> 
  8.     <input type="submit" value="login"/> 
  9.   </form> 
  10. </body> 
  11. </html>)"; 
  12.    
  13. const char * succeed = "" 
  14. "<html>" 
  15. "<body>" 
  16. "<h1>login succeed</h1>" 
  17. "</body>" 
  18. "</html>"
  19.  
  20. const char * failing = "" 
  21. "<html>" 
  22. "<body>" 
  23. "<h1>login failing</h1>" 
  24. "</body>" 
  25. "</html>"
  26.  
  27. int main() 
  28.   EventLoop::Instance()->init(); 
  29.   HttpServer server(EventLoop::Instance()); 
  30.   server.listen("127.0.0.1"80); 
  31.  
  32.   server.addGet("/", [](HttpConnect *conn, std::string_view & data) { 
  33.     conn->autoMsg(html); 
  34.   }); 
  35.  
  36.   server.addPost("/login", [](HttpConnect *conn, std::string_view & data) { 
  37.     HttpParam hp(data); 
  38.     if (hp.getStr("user") == "jw" && hp.getStr("pass") == "1111"
  39.     { 
  40.       conn->autoMsg(succeed); 
  41.     } 
  42.     else 
  43.     { 
  44.       conn->autoMsg(failing); 
  45.     } 
  46.   }); 
  47.  
  48.   return EventLoop::Instance()->run(); 

mysql和线程池

这次我们用lua示例:

  1. local config = DBConfig:new() 
  2. config.device = "mysql" 
  3. config.ip = "127.0.0.1" 
  4. config.dbname = "jw_test" 
  5. config.user = "root" 
  6. config.pswd = "1111" 
  7. config.port = 3306 
  8.  
  9. pool = DBThreadPool:new(config) 
  10. pool:create(1
  11.  
  12. func = function(err, result) 
  13.   while(result:fetch()) 
  14.   do 
  15.     local id = result:getInt32() 
  16.     local num = result:getInt32() 
  17.     local name = result:getString() 
  18.  
  19.     local str = "id:" .. id .. ", num:" .. num .. ", name:" .. name 
  20.     print(str) 
  21.   end 
  22. end 
  23.  
  24. function exec() 
  25.   local sql = SqlCommand:new("select * from test where id = ?"
  26.   sql:pushInt32(1
  27.   sql:addToPool(pool, func) 
  28. end 
  29.  
  30. event_init() 
  31. exec() 
  32. timer = UTimer:new() 
  33. timer:start(function () 
  34.     pool:update() 
  35.   end, 1010
  36. event_run() 

任意扩展进程节点

你可以任意扩展你的进程,示例:

base进程 cell进程 db进程
start engine.exe base.lua start engine.exe cell.lua start engine.exe db.lua

提供一个serialization序列化工具

类似于c++的语法,写起来非常简单,示例:

  1. struct testmsg 
  2.   int32 x 
  3.   int32 y 
  4.   int32 z 
  5.   int8 state 
  6.   vector<int32> vec 
  7.    
  8.   read{ 
  9.     [x, y, z, state] 
  10.     if(state == 1
  11.     { 
  12.       [vec] 
  13.     } 
  14.   } 
  15.   write{ 
  16.     [x, y, z, state, vec] 
  17.   } 

通过serialization工具可以将协议的描述文件生成c++和lua代码,自动生成read()和write()的函数实现,使得数据结构快速映射到SocketBuffer中。

目前serialization序列化工具为实验性,可能是脆弱的,建议使用更强大的protobuf。该项目已集成lua-protobuf,使得c++和lua之间的协议无缝衔接。

lua-protobuf的开源地址: lua-protobuf

这个示例展示了c++客户端和lua服务器之间的通讯: 快速搭建服务器Demo

构建

你需要一个modern c++17编译器

  • vs2017 测试通过
  • gcc version 9.3.0 测试通过

 

责任编辑:张燕妮 来源: Github
相关推荐

2009-07-09 17:41:41

2018-07-30 13:36:13

MacO开源应用程序

2018-11-12 11:50:10

开源发票工具Web

2018-01-09 11:09:42

RESTSOAP开源

2022-02-21 20:56:12

Linux开源网页浏览器

2012-06-13 09:23:46

虚拟化

2020-05-13 09:22:51

Linux开源缓存工具

2024-10-17 10:51:33

2018-06-13 09:00:00

2023-07-06 21:58:43

LinuxPDF编辑器

2021-01-19 13:30:52

Linux播放器互联网

2013-01-24 13:26:40

服务器机房IT部署

2010-12-14 07:50:37

OracleSolaris 11

2014-04-04 17:13:13

iOSAndroid开发技巧

2018-01-02 15:43:43

微信小程序小游戏

2020-12-11 09:06:50

异常监控云服务

2022-03-21 09:25:50

Kubernetes开源DevSecOps

2023-08-09 13:46:39

2020-10-10 09:19:58

JavaScript开发技术

2020-05-07 10:40:37

Web工具CSS
点赞
收藏

51CTO技术栈公众号