游戏服务器之热更新代码

作者: 王广帅 | 来源:发表于2018-06-03 01:26 被阅读16次

对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,JVM给我们提供了一些接口,可以简单做一些热更新。修复一些小Bug而不用重启服务。

JVM可以给运行中的服务器绑定一个代理,在这个代理中可以拿到Instrumentation 这个类的实例,它可以让用户手动修改jvm中的class类,对它进行热更新,但是有一点,用于热更新的新类和老的类方法签名必须一样,即不能修改方法的名字,参数类型,还有修改声明的字段。只能修改方法体里面的代码。一般的小bug都是方法体内的逻辑漏洞,不会做很多大的修改,所以这种方式还是能满足我们的需要求的。

现在我们分三个项目:

1,GameServer 即我们正常的游戏服务器。

2,LoadAgent  这个是热更新的代理项目,热更新的操作就在这里面执行。

3,GameServerHotBoot    这个项目是用来把LoadAget代理和GameServer进行绑定的。

JDK代理的两种方式:

1.premain方式是Java SE5开始就提供的代理方式,但其必须在命令行指定代理jar,并且代理类必须在main方法前启动,它要求开发者在应用启动前就必须确认代理的处理逻辑和参数内容等等

2.agentmain方式是JavaSE6开始提供,它可以在应用程序的VM启动后再动态添加代理的方式

应用场景:

premain这种方式必须在jar包启动的时候进行指定,它是运行在项目的main方法之前的,即项目启动时:

java – javaagent:LoadAgent.jar -jar GameServer.Jar

但是正常的生产环境下,一般不会开启代理功能,但是在发生问题时,我们不希望停止应用就能够动态的去修改一些类的行为,以帮助排查问题,这在应用启动前是无法确定的。这时agentmain就可以做到了。所以我们采用agentmain这种方式。

1,LoadAgent实现

这个实现也比较简单,就像我们的程序入口有main方法一样,它需要一个agemtmain方法

public class GameServerAgent {

    public static void agentmain(String args, Instrumentation inst) throws Exception {

        System.out.println("agent 启动成功,开发重定义对象....");

        Class[] allClass = inst.getAllLoadedClasses();

        for (Class c : allClass) {

            if (c.getName().endsWith("TestHot")) {

                String pathname = "config\\TestHot.class";

                File file = new File(pathname);

                try {

                    byte[] bytes = fileToBytes(file);

                    System.out.println("文件大小:" + bytes.length);

                    ClassDefinition classDefinition = new ClassDefinition(c, bytes);

                    inst.redefineClasses(classDefinition);

                } catch (IOException e) {

                    e.printStackTrace();

                }

                System.out.println("转换代码。。。");

            }

        }

        System.out.println("热更新成功....");

    }

    public static byte[] fileToBytes(File file) throws IOException {

        FileInputStream in = new FileInputStream(file);

        byte[] bytes = new byte[in.available()];

        in.read(bytes);

        in.close();

        return bytes;

    }

}

对某个class的替换有两种方式

1,使用ClassFileTransformer

2,使用ClassDefinition

由于ClassDefinition比较方便,所以我们使用ClassDefinition对类进行更新。

项目源码地址:https://github.com/youxijishu/game-hot-update

热更新步骤:

1,打包LoadAgent

在使用LoadAgent的时候,需要在MANNIFEST.MF添加一些属

Agent-Class: com.xinyue.hot.agent.GameServerAgent

Can-Redefine-Classes: true

Can-Retransform-Classes: true

 这个在可以在打包的pom.xml中配置

然后使用mvn install命令即可,在target中找到生成的jar,LoadAgent-0.0.1-SNAPSHOT.jar,把它放到GameServer下的config目录下面,这里是测试,用的相对路径。

2,在GameServer中创建一个测试的类,叫TestHop.java,使用里面有一个输出方法,打印1,然后使用mvn install进行编译,在target/classes中找到这个类,把它也复制到GameServer的config路径下面。

3,把TestHop类中的输出修改为2,运行GameServer,这时会输出pid和2

4,把pid复制到GameServerHotUpdate的HotUpdateMain类中,当然,在实际应用中也可以通过args传进来。然后运行HotUpdateMain,等会儿就会输出结果

这时我们发现类的输出变化了,没有热更之前输出是的2,热更新之后,输出的是1.说明,热更新成功了。

项目源码地址:https://github.com/youxijishu/game-hot-update


                                                        QQ群交流:66728073,更多文章:http://www.coc88.com

相关文章

  • 游戏服务器之热更新代码

    对于运行良好的游戏来说,停服一分就会损失很多收益。因为有些小bug就停服就划不来了。在使用Java开游戏服务器时,...

  • 【文集】Unity的热更新

    热更新对游戏很重要,但是unity自身是不支持热更新的,因此这方面还是有不少方案和文章 Unity热更新之LuaI...

  • GIT使用命令

    git pull(更新服务器代码到本地,若命令执行成功,则更新代码成功)git push(更新本地代码到服务器,若...

  • Lua脚本热更新

    本文继续来写一下脚本代码的热更新在游戏客户端或服务端的实现,之前写了一篇【客户端python热更新】里面提到热更新...

  • codepush4之linux下配置自己服务器

    codepush热更新codepush2之配置自己的服务器codepush3之Android原生引用集成codep...

  • Ionic1 APP代码热更新

    功能描述 APP热更新:不需要重新打包,将更改的代码上传到服务器,打开APP时,APP会自行到服务器检测最新...

  • 自动 部署 java 后台 项目

    一、序言 java 后台项目部署到服务器时,需要更新代码、打包、上传代码、备份服务器包、更新代码、停止服务、启...

  • 2019-07-17

    子游戏热更新资源的目录配置 热更新资源包zip目录是:game/yule/游戏名称

  • ionic3-热更新code-push常用命令

    给app在热更新服务器上创建应用 删除应用 查看热更新服务器上有哪些应用 发布应用 options参数--depl...

  • 热更新

    游戏更新分为两种,一种是游戏内热更,这个不分渠道,所有的游戏包都去游戏的热更服务器去加载资源(一般是资源文件和非底...

网友评论

    本文标题:游戏服务器之热更新代码

    本文链接:https://www.haomeiwen.com/subject/lzwrsftx.html