武侠世界2-健壮性

前几周就获得的武侠世界2的源代码,一直没有时间表去看。从网上搞来的武侠世界2的源代码,能编译通过,大的问题没有,小问题还是挺多。其它的细节,大家其实可以在网上搜索一下。下面的游戏运行的截图:我还把角色升到2级呢,废话少说,直奔主题。1、在windows下代码的健壮性打开World.sln,工程的main函数在World.cpp里面。开始部分我们能看到#ifdefined(…

大家好,又见面了,我是你们的朋友全栈君。

前几周就获得的武侠世界2的源代码,一直没有时间表去看。从网上搞来的武侠世界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);调试窗口输出情况

武侠世界2-健壮性

很明显调试窗口告诉你有一块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

如有不正确,欢迎交流讨论!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/124562.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 电脑蓝屏错误代码0x000000ED_电脑蓝屏0*000000ed怎么解决

    电脑蓝屏错误代码0x000000ED_电脑蓝屏0*000000ed怎么解决电脑蓝屏的原因很多,不同的电脑蓝屏显示的代码不同,对应的解决方法也不同。最近就有网友说自己的电脑蓝屏代码0x000000ed怎么办,不知道0x000000ed是什么意思。今天小编就教下大家修复电脑蓝屏代码0x000000ed的解决方法。0x000000ed蓝屏原因:说明I/0子系统试图加载到引导卷时失败。一般因为不正常断电导致的硬盘故障,从而导致启动时不能正常加载。具体的解决方法如下:1、先开机按f8看能否进入安全模式,能够进入的话,打开运行/输入CMD,键入命令chkdsk/f/r回…

    2022年10月8日
    0
  • 用C++实现五子棋人机对战小游戏

    用C++实现五子棋人机对战小游戏如何用C++实现五子棋小游戏呢?五子棋可谓是家喻户晓了,在科技如此发达的今天,我们能不能用电脑实现五子棋人机对弈呢?答案当然是可以的首先,思考一下我们需要完成哪些步骤1、打印棋盘(使用二维数组即可)2、判断胜负(可以考虑深搜,但是暴力似乎能让代码更简洁)3、思考下一部棋该怎么走先从最简单的一部开始:打印棋盘voidout(){for(inti=0;i<=24;i++){for(intj=0;j<=24;j++){if(

    2022年6月16日
    60
  • 浅谈C++中的那些内存泄露

    浅谈C++中的那些内存泄露

    2022年1月31日
    36
  • Python break 和 continue 语句

    Python break 和 continue 语句在Python中,break和continue语句用于改变普通循环的流程。通常情况下,循环遍历一段代码,直到判断条件为False。但有时,可能会希望不检测判断条件就可以终止当前迭代,甚至是整个循环。这种情况下,就需要使用break和continue语句。

    2022年6月10日
    25
  • java钩子函数(javasocket钩子)

    也不知道我理解的对不对,欢迎大家讨论!自己写了个钩子函数,我理解的钩子函数:publicinterfaceTransactioner{Stringwedontknow();}publicabstractclassGouZi{publicabstractvoidgouzi(Transactione…

    2022年4月13日
    142
  • java cloneable 接口_Cloneable 接口 记号接口(标记接口)「建议收藏」

    java cloneable 接口_Cloneable 接口 记号接口(标记接口)「建议收藏」Cloneable接口指示了一个类提供了一个安全的clone方法。首先了解Object.clone()方法:clone是Object超类的一个protected方法,用户代码不能直接调用这个方法。Object的子类只能调用Object超类中受保护的clone方法来克隆它自己的对象,必须重新定义clone为public才能允许所有方法调用这个类的实例的clone方法克隆对象。clone方法的作用:…

    2022年8月31日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号