用lua_tinker将lua脚本嵌入到游戏服务器

简介:

      忙中偷闲,经过几天的努力,将lua脚本嵌入到系统中。之前公司的时候,偌大一个服务器全部使用C++编写,对于新手经常发生一些宕机事件,被主程责骂。在后来接触的一些人中,发现很多公,都已经引入lua来适应多变的环境和敏捷开发!正如一个主程所说的,在n年前网易已经脚本为王了,现在很多公司拿着C++不放,作为开发人员不苦逼才怪! 想想在广州开发游戏的日子,每次在群里面看到运维说某某服务器上面有coredump文件时,总是惊出冷汗,赶紧用gdb去查询,是哪行代码引起的宕机;还要应对主程的责骂!其实不仅是程序,就是策划也经常因为配置文件的问题引起宕机!引入lua,不仅是为了程序开发的方便,更是为了应对苛刻的运营商,新手的逻辑Bug等。在这些方面lua所表现出来的优异,自是不必说。再加上其小巧灵活,嵌入方便,用来嵌入到游戏服务器之中,处理逻辑实在是太方面了!

     在底层通讯方面还是传统的C++ 和 epoll 或者iocp ,在成功接收到客户端的消息之后,按照协议将其封装成MessageBlock的结构(关于MessageBlock ,可以参考我之前的博客 http://www.cnblogs.com/archy_yu/archive/2012/09/07/2674909.html ),传递给逻辑线程,逻辑线程,在消息队列里面取消息,然后处理,引入lua之后,就是要将这个MessageBlock类的对象传递给lua,让lua来处理!那么好,我们要将必要的接口暴漏给lua,为了方便在lua 和 C++之间协调,我们引入lua_tinker库

     为了将接口暴漏给lua,我们在类MessageBlock 中添加了一个新的成员函数!如下面的代码:


class MessageBlock
{
    ...
    ///
    int write_char(const char value);
    int write_short(const short value);
    int write_int(const int value);
    int write_string(const char* ss);
    char read_char();
    short read_short();
    int read_int();
    char* read_string();
}
 
int MessageBlock::write_char(const char value)
{
    (*this) << value;
    return 0;
}
 
int MessageBlock::write_short(const short value)
{
    (*this) << value;
    return 0;
}
 
int MessageBlock::write_int(const int value)
{
    (*this) << value;
    return 0;
}
 
int MessageBlock::write_string(const char* ss)
{
    (*this) << ss;
    return 0;
}
 
char MessageBlock::read_char()
{
    char a;
    (*this) >> a;
    return a;
}
 
short MessageBlock::read_short()
{
    short s=0;
    (*this) >> s;
    return s;
}
 
int MessageBlock::read_int()
{
    int i=0;
    (*this) >> i;
    return i;
}
 
char* MessageBlock::read_string()
{
    static char ss[150];
    (*this) >> ss;
    return ss;
}

<br>

  之前数据的拼接和取值,我都是重载了操作符,为了配合lua的调用,这里添加上述接口! 我们通过使用lua_tinker将这些接口暴漏给Lua。关于如何引入lua_tinker和lua_tinker的介绍请参考百度,或者联系作者!


extern "C"
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
};
 
#include "lua_tinker.h"
 
<span style="color: rgb(255, 0, 0);">//包含必要的头文件</span>
 
int GameMonitor::lua_init()
{
    this->L = lua_open();  <span style="color: rgb(255, 0, 0);">//函数是用于打开Lua中的所有标准库,如io库、string库等。</span>
 
    luaopen_base(this->L);  //
    luaopen_string(this->L);
 
 
    return 0;
}
 
int GameMonitor::lua_class()
{
       //注册MessageBlock 到lua
    <span style="color: rgb(255, 0, 0);">lua_tinker::class_add<MessageBlock>(this->L,"MessageBlock");</span>
 
    return 0;
}
 
int GameMonitor::lua_method()
{
        <span style="color: rgb(255, 0, 0);">//注册MessageBlock 的构造函数等</span>
    <span style="color: rgb(136, 136, 136);">lua_tinker::class_con<MessageBlock>(this->L,lua_tinker::constructor<MessageBlock,int>);
    lua_tinker::class_def<MessageBlock>(this->L,"write_int",&MessageBlock::write_int);
    lua_tinker::class_def<MessageBlock>(this->L,"read_int",&MessageBlock::read_int);
 
    lua_tinker::class_def<MessageBlock>(this->L,"write_string",&MessageBlock::write_string);
    lua_tinker::class_def<MessageBlock>(this->L,"read_string",&MessageBlock::read_string);</span>

    如此,我们就可以像这样来处理消息,如下面的代码(MsgPrc.lua):


--msg = MessageBlock(1024)
--
--msg:write_int(10)
--
--print (msg:read_int())
--
--a = "sdsdcds"
--
--msg:write_string(a);
--
--print (msg:read_string())
 
local s_msghead = {}
 
local msg
<br>--主逻辑,死循环,用来处理消息
local function run_logic()
    while true do
        msg = peek_msg()
        if msg == nil then
            sleep(1)
        else       
            process_msg(msg)
        end
    end
end
 
local function process_msg(msg)
    msg_head = msg:read_int()
    if s_msghead[msg_head] then
        s_msghead[msg_head](msg)
    end 
end
<br>--在此注册消息处理逻辑
local function init_msghead()
    s_msghead[10001] = process_10001
    s_msghead[10002] = process_10002
end
 
local function process_10002(msg)
    msg.read_int(a);
    msg.read_string(b);
    --process
    remsg = MessageBlock(50);
    remsg.write_int(100)
    remsg.write_string("ok");
    respond_to_client(remsg);   
end
 
--process_10001
 
 
init_msghead()
run_logic()

 这样就实现了用lua来处理所有的逻辑!

      我们调整一下代码逻辑,就可以实现诸如热更新的功能,来应对日益激烈的页游山寨竞争!之前就有听说过,说为什么搞IT的人看起来都很闲,说运维总是在重启,web前端开发者总是在上传,C++开发者总是在编译。因为语言特性,C++开发者总要面临编译的问题,对于服务器代码,如果全是C++来编写,必然也是要面对这个问题,据说之前公司一个团队的后端代码要编译三个小时才能编译出可执行文件来。用lua来写主逻辑,其他的底层代码用库封装,岂不是又解决了一个问题!

      欢迎讨论!!!

相关文章
|
7月前
|
安全 Linux
阿里云linux服务器使用脚本通过安全组屏蔽异常海外访问ip
公网网站可能会遭受黑客攻击导致访问异常,使用此脚本可以屏蔽掉异常IP 恢复访问。也可自行设置定时任务定期检测屏蔽。
584 28
|
9月前
|
缓存 NoSQL 搜索推荐
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
本文介绍了如何通过Lua脚本在Redis中实现分布式锁的原子性操作,避免并发问题。首先讲解了Lua脚本的基本概念及其在Redis中的使用方法,包括通过`eval`指令执行Lua脚本和通过`script load`指令缓存脚本。接着详细展示了如何用Lua脚本实现加锁、解锁及可重入锁的功能,确保同一线程可以多次获取锁而不发生死锁。最后,通过代码示例演示了如何在实际业务中调用这些Lua脚本,确保锁操作的原子性和安全性。
493 6
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
|
9月前
|
NoSQL Redis 数据库
Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
通过本文的介绍,我们详细讲解了 Lua 脚本在 Redis 中的作用、`eval` 命令的使用方法以及 `redis.call` 和 `redis.pcall` 的区别和用法。通过合理使用 Lua 脚本,可以实现复杂的业务逻辑,确保操作的原子性,并减少网络开销,从而提高系统的性能和可靠性。
455 13
|
消息中间件 NoSQL Java
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
522 0
|
11月前
|
监控 安全
公司用什么软件监控电脑:Lua 脚本在监控软件扩展功能的应用
在企业环境中,电脑监控软件对保障信息安全、提升效率至关重要。Lua 脚本在此类软件中用于扩展功能,如收集系统信息、监控软件使用时长及文件操作,向指定服务器发送数据,支持企业管理和运营。
181 6
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
803 1
|
缓存 分布式计算 NoSQL
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
154 2
|
存储 JSON Ubuntu
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?
|
运维 监控 数据库
自动化运维:使用Python脚本实现服务器监控
【8月更文挑战第31天】在这篇文章中,我们将探索如何利用Python编写简单的脚本来实现对服务器的基本监控。通过学习和应用这些技术,你可以快速检测服务器的状态,包括CPU使用率、内存占用和磁盘空间等关键指标。这不仅有助于及时发现问题,还能提升运维效率。文章将逐步引导你理解监控的重要性,并展示如何从零开始构建自己的监控工具。
|
监控 数据挖掘 Linux
Linux服务器PBS任务队列作业提交脚本的使用方法
【8月更文挑战第21天】在Linux服务器环境中,PBS任务队列能高效管理及调度计算任务。首先需理解基本概念:作业是在服务器上执行的任务;队列则是等待执行任务的列表,具有不同的资源限制与优先级;节点指分配给作业的计算资源。
2096 4

热门文章

最新文章