游戏开发论坛

 找回密码
 立即注册
搜索
楼主: yukun84

网络游戏服务器内存补丁技术(更新x64相关)

[复制链接]

1

主题

15

帖子

35

积分

注册会员

Rank: 2

积分
35
发表于 2009-7-28 14:02:00 | 显示全部楼层

Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

这是非常不切实际的,你考虑的只是说这个BUG需要修改的代码非常非常少,涉及到的面非常非常小,各个逻辑关系影响十分有限才行。现在出现BUG的情况基本上要修改的代码涉及到很多方面的问题,特别是共享数据的访问,假如你在程序正在跑着那段代码的时候修改了内存,那么你如何保证他的EIP不会出现错误?你如何保证他已经跑了一段错误的代码,这时你更新新的进去他又在新的上面跑,你如何保证前后数据的一致?更何况你新增代码的话他所需要的内存区域就会变大,你如何保证你修改的地方的下面那段内存不被挤压?可能你会说我另外写个函数然后直接在要修改的地方跳转,可是你一个那么多代码的项目到处是CALL跳转的话怎么保证后期维护的一致性?

15

主题

368

帖子

406

积分

中级会员

Rank: 3Rank: 3

积分
406
 楼主| 发表于 2009-7-28 14:41:00 | 显示全部楼层

Re: Re:网络游戏服务器内存补丁技术(附测试实例及源代

xhmff9: Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

这是非常不切实际的,你考虑的只是说这个BUG需要修改的代码非常非常少,涉及到的面非常非常小,各个逻辑关系影...


莫急莫急,我一一给你答案:

假如你在程序正在跑着那段代码的时候修改了内存,那么你如何保证他的EIP不会出现错误?
我的贴子里这点已经写得很明白了。


你如何保证他已经跑了一段错误的代码,这时你更新新的进去他又在新的上面跑,你如何保证前后数据的一致?
你指什么数据的一致性呢?给个详细点的说明。


更何况你新增代码的话他所需要的内存区域就会变大,你如何保证你修改的地方的下面那段内存不被挤压?可能你会说我另外写个函数然后直接在要修改的地方跳转,可是你一个那么多代码的项目到处是CALL跳转的话怎么保证后期维护的一致性?
对啊对啊,就是跳转。主贴里都说得很清楚了。嗯?后期维护一致性?有这个问题么?只是临时打个补丁,不涉及到正式的代码改动(这种改动就算想加到后期的维护代码中恐怕也是不易的吧。。。)




还有什么问题欢迎提出来,大家一起思考,把它的不足之处一一解决。

1

主题

15

帖子

35

积分

注册会员

Rank: 2

积分
35
发表于 2009-7-28 15:33:00 | 显示全部楼层

Re: Re: Re:网络游戏服务器内存补丁技术(附测试实例及源

yukun84: Re: Re:网络游戏服务器内存补丁技术(附测试实例及源代码)



莫急莫急,我一一给你答案:

假如你在程序正在跑着那段代码的时候修改了内存,那么你如何保证他的EI...

你如何保证他已经跑了一段错误的代码,这时你更新新的进去他又在新的上面跑,你如何保证前后数据的一致?
你指什么数据的一致性呢?给个详细点的说明。
假如你有两个有BUG的函数,且这两个函数是有前后依赖关系的,后一个函数计算的值需要前一个函数计算值后传入参数计算之,此时代码跑完第一函数后你把补丁打进去,修改后的第一函数和未修改的第一函数所计算的值是不同的,那么就会出现线程拿着错误的第一个函数计算的值给正确的第二个函数去计算,那么这样得出的值是否有问题?这只是一个非常乐观的运行环境,有可能是线程跑着一半的错误代码的时候你替换了新的进去,那么这个时候不仅仅是我上面所提到的问题那么简单了,可能局部变量等等一切在这段代码里面出现的数据都有可能出错!而且很可能是内存访问错误,直接造成崩溃!
当在多线程的环境当中时(网络部分使用多线程很正常,逻辑部分我推崇的是单线程处理)就更可怕了。
还有就是关于代码一致性的问题,你打补丁的代码肯定要和库里的代码一致,不然下个版本出来又出现上个版本的问题那就惨了。如果这个时候你用这种办法的话就会造成代码不一致,单元测试困难了,很有可能就会是到处都是CALL,看起来一头雾水,今天也许记得是什么,等过了明天可能就是天书了!

15

主题

368

帖子

406

积分

中级会员

Rank: 3Rank: 3

积分
406
 楼主| 发表于 2009-7-28 16:59:00 | 显示全部楼层

Re: Re: Re: Re:网络游戏服务器内存补丁技术(附测试实例及

xhmff9: Re: Re: Re:网络游戏服务器内存补丁技术(附测试实例及源代码)


你如何保证他已经跑了一段错误的代码,这时你更新新的进去他又在新的上面跑,你如何保证前后数据的一致?...


你如何保证他已经跑了一段错误的代码,这时你更新新的进去他又在新的上面跑,你如何保证前后数据的一致?
你指什么数据的一致性呢?给个详细点的说明。
假如你有两个有BUG的函数,且这两个函数是有前后依赖关系的,后一个函数计算的值需要前一个函数计算值后传入参数计算之,此时代码跑完第一函数后你把补丁打进去,修改后的第一函数和未修改的第一函数所计算的值是不同的,那么就会出现线程拿着错误的第一个函数计算的值给正确的第二个函数去计算,那么这样得出的值是否有问题?这只是一个非常乐观的运行环境,有可能是线程跑着一半的错误代码的时候你替换了新的进去,那么这个时候不仅仅是我上面所提到的问题那么简单了,可能局部变量等等一切在这段代码里面出现的数据都有可能出错!而且很可能是内存访问错误,直接造成崩溃!


所以我的贴子里第一条要注意的就是代码正在运行的处理嘛。在服务器的逻辑轮循完成时检测内存补丁再打上去。做到这一点没什么难度吧?打完补丁再继续下一次的服务器轮循。


当在多线程的环境当中时(网络部分使用多线程很正常,逻辑部分我推崇的是单线程处理)就更可怕了。

觉得给网络模块多线程环境打补丁太危险就不打嘛(基本上可以认为网络模块出问题还能继续运行就说明网络模块的问题不大。这玩意是要么不出问题要么出大问题)。。。说句实话,碰到正在运行的代码的机率微乎其微。。因为时间绝大部分消耗在Sleep上或是网络内核的操作上。逻辑嘛就照我上面的去处理。


还有就是关于代码一致性的问题,你打补丁的代码肯定要和库里的代码一致,不然下个版本出来又出现上个版本的问题那就惨了。如果这个时候你用这种办法的话就会造成代码不一致,单元测试困难了,很有可能就会是到处都是CALL,看起来一头雾水,今天也许记得是什么,等过了明天可能就是天书了!

首先要弄清临时解决方案和正式解决方案的区别。我在贴里已经说过,不排除某个问题要解决会涉及到很多机制的修改,但临时解决方案的代码很少,而且正常情况下是不应该入库的。就算不是用内存补丁而是改C++代码,也不应该入库。还有就是补丁没有C++代码,甚至连汇编代码也没。它只是一段内存,它可以视作不需要维护的东西。(你不会认为只是出个内存补丁,正式的C++代码里却不解决问题留给内存补丁吧。。。)

1

主题

15

帖子

35

积分

注册会员

Rank: 2

积分
35
发表于 2009-7-28 17:14:00 | 显示全部楼层

Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

所以我的贴子里第一条要注意的就是代码正在运行的处理嘛。在服务器的逻辑轮循完成时检测内存补丁再打上去。做到这一点没什么难度吧?打完补丁再继续下一次的服务器轮循。
按照这个理论的话 那么每个函数都得做检测了,那么这样效率问题就来了,如果你说在这个线程的最外层循环做判断那么线程处理后续逻辑任务的时候就会出现积压,更何况你无法在写错误代码的时候就预见到这里出错,所以理论上会在任何一个地方打上补丁,那么你要做得事情就比重新编译一次需要付出的代价大太多了,如果你的老板允许你的这种方案的话那我真的得佩服一下他,能冒那么大的风险干这事。
这个方法不要出问题,一旦出现一次小小的问题就有可能击溃你的数据造成回档重来的风险,这个时候不被玩家问候祖宗18代的话那真是大幸也!

15

主题

368

帖子

406

积分

中级会员

Rank: 3Rank: 3

积分
406
 楼主| 发表于 2009-7-28 18:22:00 | 显示全部楼层

Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

在每个服务器轮循完前后或是轮循前检测一次看有没有内存补丁基本不消耗时间的(要觉得还不过瘾就别每次循轮检测,过一秒钟检测一次嘛)。至于你说的后续逻辑任务出现积压。。。老大你不会以为真正的网络游戏服务器也像我写的示例一样是通过std::cin接受输入内存补丁的吧。。。

内存补丁是很好测试的,写得有没有问题一测便知。就光从这种技术上来说,一台服务器上跑得没问题,在其他服务器上就肯定也没问题。(如果因为某些逻辑原因导致无法测试代码的情况,即使改C++代码该出问题的还是会出问题,这已经和内存补丁技术无关了)。还有就算任何修改,包括C++代码层面的修改,难道改了就不测试的?

15

主题

368

帖子

406

积分

中级会员

Rank: 3Rank: 3

积分
406
 楼主| 发表于 2009-7-28 18:32:00 | 显示全部楼层

Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

还是上面的示例,再更新个内存补丁:

00406410:00000000000000000000000000000000000000000000000000$b3fdcafdb2bbc4dcceaa30a3acc7ebd6d8d0c2cae4c8eba3ba|00401B20:B800000000B800000000B800000000B800000000B800000000B800000000B800000000B800000000B800000000$8B44240483F8007518A14C404000681064400050E8F7160000909090E90F150000A14C404000E91E1500009090|00403064:A14C404000$E9B7EAFFFF

复制下来输入,如果打补丁失败则看一下是否有带回车符一类。
这个补丁的功能是当输入的除数为0则会提示再次输入,直到你输入一个不为0的数为止。

1

主题

15

帖子

35

积分

注册会员

Rank: 2

积分
35
发表于 2009-7-28 18:47:00 | 显示全部楼层

Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

你判断有没有内存补丁的时候需要锁吧?加锁和不加锁耗费的时间能看成是不消耗时间?如果你不加锁判断,那我真觉得你太厉害了,并且怀疑你是否真写过服务器了!
我的服务器单个进程当中最少时100个用户连接,最多时1000个连接,原子时间内生成的逻辑任务以千计算,你停那一下下可能就积压出上千个任务,你说这个是不是问题呢?
服务器是个高吞吐、高任务、不确定性十分复杂的运行环境,一旦出现问题将是灾难性的,所以你提出的方法在理论上是可行的,但在实际应用中估计没几个勇敢的人敢这么做。内存补丁这种形式只适合在运行环境要求非苛刻、处理问题不复杂的地方,就算崩溃了可以重来影响不大,但在服务器上一个崩溃就有可能扣掉你一个月的工资,所以这种方法还是三思而后行为妙!

15

主题

368

帖子

406

积分

中级会员

Rank: 3Rank: 3

积分
406
 楼主| 发表于 2009-7-28 19:06:00 | 显示全部楼层

Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

小伙子别鸡冻嘛~

以我的经验来看,我觉得应该不带来什么开销(就算每次轮循都检查),更不会积压出上千任务。。。。。如果服务器的实际情况是每秒的任务吞吐量是十万级别的,上千个任务倒还真有可能。。不过以这种级别的处理速度,上千任务也算不上什么了。

当然,还有更多方法可以不加锁,比如它的输入方式就是一条特殊的消息包,和处理普通用户的一样。只不过收到了不马上处理,而是放着等轮循过后再处理。

或许最终这个性能问题我写得很烂,最严重的后果是把每秒检测一次变成每十秒检测一次而已(嗯。。其实我看一分钟检测一次似乎也问题不大)。

所以这不是什么很恐怖的问题。


危险肯定是有的,但幸运的是因为它的特殊性使得很容易通过测消除危险。内存补丁的代码本身不会太多,加上一出问题就是严重问题而不会隐藏,所以在测试这一环节上就能把危险排除。再加上如果打补丁,也肯定不会是所有服务器同时打上。先打几组,测试一会再给其他服务器打补丁,这个危险基本上可以排除。


呃。。。服务器崩溃我倒是遇到过很多次,但扣我一个月工资的情况倒是没遇到过。。。。

15

主题

368

帖子

406

积分

中级会员

Rank: 3Rank: 3

积分
406
 楼主| 发表于 2009-7-28 19:17:00 | 显示全部楼层

Re:网络游戏服务器内存补丁技术(附测试实例及源代码)

其实这贴的目的就是要讨论出危险性在哪里,尽量消除危险,使它变得更为简单易用(当然这只是相对的。比起C++它肯定还是要复杂)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-20 00:55

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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