前几周就获得的武侠世界2的源代码,一直没有时间表去看。从网上搞来的武侠世界2的源代码,能编译通过,大的问题没有,小问题还是挺多。其它的细节,大家其实可以在网上搜索一下。下面的游戏运行的截图:
我还把角色升到2级呢,废话少说,直奔主题。
1、在windows下代码的健壮性
打开World.sln,工程的main函数在World.cpp里面。开始部分我们能看到
#if defined(__WINDOWS__)
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
_CrtSetDbgFlag(_CrtSetDbgFlag(0)
|_CRTDBG_LEAK_CHECK_DF);
#endif
这段代码。
SetUnhandledExceptionFilter就是设置异常捕获函数,这里原捕捉函数就是MyUnhandledExceptionFilter了,也就是说,系统原来打印异常有默认的处理函数,现在的异常处理将会跳到你指定的函数,这对于游戏服务端是非常重要的,因为设置异常捕获函数,在系统存在异常的时候,我们还可以使游戏继续运行下去,争取了一些时间去修改系统的bug。详细的应用例子可以查看下面的例子
http://blog.sina.com.cn/s/blog_5d8945610100pnzg.html
而_CrtSetDbgFlag能检测内存泄露情况。内存泄露危害,特别是游戏服务端不重启运行一段较长时间,其危害性更加严重。而_CrtSetDbgFlag能在程序调试时发现内存泄露的情况,这样将大大减少程序内存泄露情况。
#include <iostream>
#include <crtdbg.h>
using namespace std;
void main()
{
int * c = new int[5];
c[0]=1;
c[1]=2;
_CrtSetDbgFlag(_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF);
int * p = new int[3];
cout << "Test Memory Leak" << endl;
}
按下F5,运行程序。
你可以对比注释掉_CrtSetDbgFlag(_CrtSetDbgFlag(0) |_CRTDBG_LEAK_CHECK_DF);和没有注释_CrtSetDbgFlag(_CrtSetDbgFlag(0)
|_CRTDBG_LEAK_CHECK_DF);调试窗口输出情况
很明显调试窗口告诉你有一块12字节长和一块20字节长的内存没有释放,其中20字节长的内存数据是01 00 00 00 02 00 00 00 CD CD CD CD CD CD CD CD,正好是我们程序赋值了的数据。
2、在linux下代码的健壮性
看到上面的代码,这只是在windows下运行才会这样,那样在linux下武侠世界又是怎样做的呢?根据我过往的经验,我搜索一下程序有关信号的代码,果然,给我搜索到了。
GameUtil.h
class ExceptionHandler
{
public:
ExceptionHandler();
static VOID Handler(INT);
};
extern ExceptionHandler g_ExceptionHandler;
GameUtil.cpp
ExceptionHandler::ExceptionHandler()
{
#ifdef __LINUX__
signal(SIGSEGV, Handler);
signal(SIGFPE, Handler);
#endif
}
VOID ExceptionHandler::Handler(INT)
{
DumpStack("ExceptionHandler::Handler");
exit(0);
}
ExceptionHandler g_ExceptionHandler;
但是在武侠世界中,当程序捕捉到signal后,在Handler中打印了信息后就退出了程序,这应该不太适合游戏服务端的要求,因为游戏在实际运行存在太多的不确定性了。就像我之前的说的,我们希望的是,出现了异常还能继续运行一段时间。因此我写一段代码来实现这个想法。写这段代码的灵感恰恰来自
extern ExceptionHandler g_ExceptionHandler;
和在构造函数里面初始化signal。
这样写法的优势是:只要声明一次,在全局都有效。
#ifndef SHOWCRASH_H
#define SHOWCRASH_H
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <execinfo.h>
/*
* ??????????????SETJMP??
* ???SETJMP????SETJMP???CRASH???????SETJMP?
* ???SETJMP???CRASH???????SETJMP
*/
class ShowCrash
{
public:
ShowCrash();
static void CrashFunction(int);
static const int MAX_JMP_BUF = 16;
static const int MAX_CALLSTACK_DEPTH = 32;
enum buffername
{
BUF_MAIN,
BUF_COUNT
};
static void SetIndex(int index){buf_index = index;}
static int GetIndex(){return buf_index;}
static int buf_index;
private:
};
#define SETJMP(index)\
setjmp(buff[index]);\
ShowCrash::SetIndex(index);\
extern ShowCrash g_showcrash;
extern jmp_buf buff[ShowCrash::MAX_JMP_BUF];
#endif
#include "showcrash.h"
ShowCrash g_showcrash;
jmp_buf buff[ShowCrash::MAX_JMP_BUF];
int ShowCrash::buf_index = 0;
ShowCrash::ShowCrash()
{
struct sigaction act, oact;
act.sa_handler = CrashFunction;
sigemptyset(&act.sa_mask); //娓呯┖姝や俊鍙烽泦
act.sa_flags = SA_NODEFER;
sigaction(SIGINT, &act, &oact);
sigaction(SIGABRT, &act, &oact);
sigaction(SIGSEGV, &act, &oact);
sigaction(SIGFPE, &act, &oact);
sigaction(SIGBUS, &act, &oact);
sigaction(SIGTRAP,&act,&oact);
// buf_index = 0;
}
void ShowCrash::CrashFunction(int)
{
void *traceback[MAX_CALLSTACK_DEPTH];
char cmd[512] = "addr2line -f -e GameEngine";
FILE *fp = popen(cmd, "w");
int depth = backtrace(traceback, MAX_CALLSTACK_DEPTH);
for (int i = 0; i < depth && i < MAX_CALLSTACK_DEPTH; i++)
{
fprintf(fp, "%p\n", traceback[i]);
}
fclose(fp);
longjmp(buff[ShowCrash::GetIndex()],1);
}
这样就能够在出现系统异常的时候,通过setjmp和longjmp来让程序继续运行。
交流群:315249378
如有不正确,欢迎交流讨论!
分享到:
相关推荐
无证书标识可信-健壮的层次标识密码
Glue - 健壮的Go和Javascript Socket库 (可替代Socket.io)
1-客户端健壮性测试.81e0e000-bc85-11e7-9a52-9bd0f40b56c0.pdf
本文介绍了I2C串行EEPROM应用系统的健壮性设计
提高网络健壮性必杀技之——堆叠.doc
嵌入式Linux应用程序健壮性研究,孙新贺,王晓辉,嵌入式Linux操作系统以其出色的稳定性、可靠性在嵌入式系统领域得到日益广泛的应用,嵌入式Linux操作系统现场应用复杂,控制对象多��
I2C串行EEPROM应用系统的健壮性设计.pdf
针对网格资源的不可靠性特点,提出了健壮性增强的作业执行服务的概念及其确定方法,基于该概念提出了健壮性增强的离线资源分配模型,通过将作业执行服务中对应的多个网格节点资源分配给作业冗余执行以增强其健壮性....
讲述了保持代码健壮性的小技巧和原理 更深入学习java原理
教程名称:健壮性测试方法与工具 课程目录 : 【】IO字节流节点流拷贝工具健壮性 【】Linux19-模拟宕机所有服务器角色测试MFS服务健壮性_rec 【】基于场景模型的BGP_4健壮性...
本文介绍了Java的健壮性特点,包括异常处理、断言和错误处理。同时,提供了相应的Java示例代码。 内容概要 本文档涵盖以下内容: 异常处理机制及示例 断言的使用及示例 错误处理机制及示例 学到什么 通过阅读本文...
提高DB2存储过程性能和健壮性的3个最佳实践,教你如何进行db2存储过程的优化
遍历、代码健壮性、如何看公司代码。对于刚开始编程序的童鞋来说值得看看学习一下。
健壮、优雅、灵活和易维护的软件架构是怎样炼成的?本书通过一系列优秀的文章回答了这个问题,这些文章来自于十几位当今一流的架构师。在每篇文章中,作者都向我们展示了一个著名的软件架构,并分析了什么让其具有...
机会网络路由算法在不同合作度下的健壮性是一个重要的但未被充分研究的问题,分析了机会网络中可能存在的节点间不合作的情况,定义了三种适用于不同场景的节点合作度,设计了评价方法及指标体系,通过对真实城市场景...
提高DB2存储过程性能和健壮性,不得不关注的重要点
Abstract. This paper evaluates 2D feature detection methods with respect to invariance and efficiency properties. The studied feature detection methods are as follows: Speeded Up Robust Features, ...
高可用MySQL 构建健壮的数据中心。------------------------------------------------------------------------------------------------------------------------------------------------------------------------...