游戏开发论坛

 找回密码
 立即注册
搜索
查看: 7598|回复: 7

谈谈服务器中python脚本的安全容错处理

[复制链接]

1万

主题

1万

帖子

2万

积分

管理员

中级会员

Rank: 9Rank: 9Rank: 9

积分
20468
发表于 2012-3-25 15:46:00 | 显示全部楼层 |阅读模式
来源:http://baseapp.pengyou.com/c265e4bd629300c52ca95c0f2aac2fd8fcf30a8d882e30c7/blog/1332659779

  对于一个服务器来说,不管是游戏服务器还是什么服务器,稳定性无疑是最重要,最看重的一个环节了。即使是一个微小的错误,也有可能会引起全局的流程性问题。

  服务器中的关键代码一般都是由C或者C++来实现,以获得一个较快的执行速度。而业务逻辑的可变性采用易于维护和编写的python脚本来实现,可以在易于编写和执行速度之间得到一个权衡。


  由于脚本的简单和易维护性,目前很多服务器的业务逻辑都有部分放在脚本中。目前比较流行的、与C混合编程的脚本语言有python,lua.

下面我们谈谈python的脚本安全问题。


简单介绍下python:

  Python是一门功能强大的高级脚本语言,它的强大不仅表现在其自身的功能 上,而且还表现在其良好的可扩展性上,正因如此,Python已经开始受到越来越多人的青睐,并且被屡屡成功地应用于各类大型软件系统的开发过程中。

  同时可以借助Python语言提供的API,使用C或者C++来对Python进行功能性扩展,从而即可以利用 Python方便灵活的语法和功能,又可以获得与C或者C++几乎相同的执行性能。执行速度慢是几乎所有脚本语言都具有的共性,也是倍受人们指责的一个重 要因素,Python则通过与C语言的有机结合巧妙地解决了这一问题,从而使脚本语言的应用范围得到了很大扩展。

  在由C++或者C扩展python需要关注两个问题。

一、是C++导出给python调用的接口。

  C++导出给python调用的接口,是从python脚本将参数传入C++的过程。

  导出接口模板PyObject* method(PyObject* self, PyObject* args);

  该 函数是Python解释器和C函数进行交互的接口,带有两个参数:self和args。参数self只在C函数被实现为内联方法(built-in method)时才被用到,通常该参数的值为空(NULL)。参数args中包含了Python解释器要传递给C函数的所有参数,通常使用Python的C语言扩展接口提供的函数PyArg_ParseTuple()来获得这些参数值。

  所有的导出函数都返回一个PyObject指针,如果对应的C函数没有真正的返 回值(即返回值类型为void),则应返回一个全局的None对象(Py_None),并将其引用计数增1,如下所示:

PyObject* method(PyObject *self, PyObject *args)
{
   Py_INCREF(Py_None);
   return Py_None;
}

导出接口需要注意3点:

1、注意上面红色部分。如果某导出函数没有返回对象给python,在脚本被调用时,将出现一些稀奇古怪的异常问题。

2、在将python传入的参数进行转换C++识别的数据时,需要对参数进行类型安全判断。

   如传入的是字符串,就不能对其调用Pyint_asLong. 否则可能会引起下一次脚本调用出现异常。

3、C++导出的接口如果出现异常,将会引起整次脚本调用无效。所以C++的异常自己捕捉。减小抛出范围


二、是C++调用python脚本时、对象调用和释放的问题

C++调用python脚本时,最需要注意的是python对象释放的问题。

Python往往包含大量的内存分配和释放,需要避免内存泄漏和野指针。python选择的方法就是 引用计数 。其原理比较简单:每个对象都包含一个计数器,计数器的增减与引用的增减直接相关,当引用计数为0时,表示对象已经没有存在的意义了,就可以删除了。

同时python的引用包含两种。一种是拥有一个对象,标示拥有者需要对其负责调用  Py_DECREF() 来减少引用计数。

一种是借用 一个对象,借用的对象不能调用 Py_DECREF() 来减少引用计数。借用者在不需要借用时,不保留其引用就可以了。应该避免拥有者释放对象之后仍然访问对象,也就是野指针。

针对python返回的对象,需要关注2点

1、 对拥有的对象在使用完毕后,一定要释放引用

2、  对借用的对象一定不能调用引用。



在对脚本的返回值特别需要注意返回值的类型和转换工作。

如果脚本函数无返回参数,则函数返回的类型为NoneType。。如果对该NoneType对象进行int转换,将出现异常。对返回值做如下处理比较安全。

if (PyString_Check(value)) {
    return PyString_AsString(value);
  }
  else if (value == Py_None) {
    return variant();
  }
  else if (PyBool_Check(value)) {
    return value == Py_True;
  }
  else if (PyInt_Check(value)) {
    return PyInt_AsLong(value);
  }
  else if (PyFloat_Check(value)) {
    return PyFloat_AsDouble(value);
  }
 

三、python脚本本身的异常处理

类似c++中的try/catch..

脚本中采用

try:

    …

except Exception,ex:

print Exception,":",ex

来捕获所有异常。在代码中加入异常捕捉,防止由于小范围异常导致整个逻辑出错

58

主题

1437

帖子

2207

积分

金牌会员

Rank: 6Rank: 6

积分
2207
发表于 2012-3-25 16:49:00 | 显示全部楼层

Re:谈谈服务器中python脚本的安全容错处理

服务器第一不允许的就是异常,所谓异常都是考虑不周全所致,或整体架构有问题。
异常没有范围之说,堆栈写乱掉,跳转地址都是错误的,根本谈不上恢复,
唯一可以做的就是重启服务器,但重启服务器并没有消灭异常,
只是个临时的补救措施而已。

1万

主题

1万

帖子

2万

积分

管理员

中级会员

Rank: 9Rank: 9Rank: 9

积分
20468
 楼主| 发表于 2012-3-26 11:10:00 | 显示全部楼层

Re:谈谈服务器中python脚本的安全容错处理

这里有两个因素

1、没有完美无缺的程序,在C++体系里也提供了很多异常捕获的机制,特别在一款复杂的网游里,想达到稳定完美,微微难,所以需要对异常的处理;

2、捕获异常除了是为了让服务器不立即宕机或出现不可预测的结果,同时也是为了捕捉错误的位置,以便于后面的调试和修复。

58

主题

1437

帖子

2207

积分

金牌会员

Rank: 6Rank: 6

积分
2207
发表于 2012-3-26 13:28:00 | 显示全部楼层

Re: Re:谈谈服务器中python脚本的安全容错处理

客户端有异常捕获可以理解,因为客户端要运行在不同的硬件和操作系统上,
并且大部分客户端出于保密的要求还不能输出日志。
服务器的异常真的很难理解,特定机器,特定系统,还有完善的日志输出,
要异常捕获机制实属多余,出现异常的最好办法就是立刻宕机,然后通过监控进程重新启动服务。
保持日志的中断位置给分析异常做准备。
在客户端一般异常如果超过5%,那就是非常严重的问题,但这类问题都是必现的问题。
也就是找到崩溃位置一般都是可以检查出问题的原因。客户端会有1%左右的问题是跟系统
有关的问题在某些系统的特定条件或线程特殊条件下会触发。
对于服务器来说这1%的bug是不存在,因为服务器不使用严重依赖系统的api。
第二服务器也不会有hook内存或者开启动态调试这种危害系统的行为,更不会去碰驱动这些东西。
唯一能让服务器崩溃的就是烂用指针,这个就是编程者的水平问题,
甚至可以说基本功完全不达标,也或者是因为架构本身过度复杂不可控制。
除了崩溃还依次有内存泄漏,逻辑数据异常,网络被攻击,堆栈溢出这些严重的不可逆转的错误。
崩溃也就是空指针访问的错误是外在表现最直接,跑一遍功能都能暴露出来,修改和解决也最容易的问题。
崩溃做为软件一级严重事故还能带着上线,说明质量监控体系是出现严重问题。
sea_bug: Re:谈谈服务器中python脚本的安全容错处理

这里有两个因素

1、没有完美无缺的程序,在C++体系里也提供了很多异常捕获的机制,特别在一款复杂的网游...

58

主题

1437

帖子

2207

积分

金牌会员

Rank: 6Rank: 6

积分
2207
发表于 2012-3-26 23:28:00 | 显示全部楼层

Re:谈谈服务器中python脚本的安全容错处理

多说了几句闲话自顶下

1万

主题

1万

帖子

2万

积分

管理员

中级会员

Rank: 9Rank: 9Rank: 9

积分
20468
 楼主| 发表于 2012-3-27 12:03:00 | 显示全部楼层

Re:谈谈服务器中python脚本的安全容错处理

主要是服务器突然噗吱的当掉,会导致数据无法回写DB,然后紧接着就是回档,还是比较蛋疼的。

58

主题

1437

帖子

2207

积分

金牌会员

Rank: 6Rank: 6

积分
2207
发表于 2012-3-28 06:46:00 | 显示全部楼层

Re: Re:谈谈服务器中python脚本的安全容错处理

严格的来说已经宕掉的服务器内存数据是完全不可信任的,
例如某些情况下是因为一个线程狂写数据直到把另一个线程的代码段抹掉才宕机。
我曾经遇到过虽然try-catch被触发,但进程其他线程并没有被停止,导致catch代码执行又崩溃。
虽然是个例,但从这里看这玩意不但不是什么保障,对服务来说就是坑爹的东西。
sea_bug: Re:谈谈服务器中python脚本的安全容错处理

主要是服务器突然噗吱的当掉,会导致数据无法回写DB,然后紧接着就是回档,还是比较蛋疼的。

0

主题

6

帖子

14

积分

新手上路

Rank: 1

积分
14
发表于 2012-4-1 11:03:00 | 显示全部楼层

Re:谈谈服务器中python脚本的安全容错处理

赞同gantleman的观点,fail early and fail fast 对于服务器端来说是合适的。
服务器异常之后仍然让其继续运行的最大问题在于,系统无法再保证数据的一致性,这破坏了系统所提供服务的核心价值。考虑到网游服务器会定时存档,所以短暂回档比档案异常好。
当然,如果确定局部代码的错误不会产生不可挽回的错误且不会扩散,那么用异常机制将其控制在局部并提供部分服务水平降级(某项功能暂不可用)而不是全部服务停止的做法也是可以接受的。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2025-2-28 17:02

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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