首先要说明的是:

 linux 下 比较方便可以得到 崩溃时的调用栈,win下 比较难办
 

1. linux 获取调用栈

代码奉上:
  1. #include <execinfo.h> //在头文件"execinfo.h"中声明了三个函数用于获取当前线程的函数调用堆栈
  2. #include <fcntl.h>
  3. #include <sys/resource.h>
  4.  
  5. #include <signal.h>
  6. static int _core_dump_signals[] = {
  7. SIGABRT, SIGFPE, SIGILL, SIGQUIT, SIGSEGV,
  8. SIGTRAP, SIGSYS, SIGBUS, SIGXCPU, SIGXFSZ
  9. #ifdef SIGEMT
  10. ,SIGEMT
  11. #endif
  12. };
  13. //安装崩溃时//打印当前线程的函数调用堆栈
  14. void installTrace()
  15. {
  16. struct sigaction act;
  17. size_t i;
  18. memset(&act, , sizeof(act));
  19.  
  20. act.sa_handler = &CLog::LogTrace;
  21. sigfillset(&act.sa_mask);
  22.  
  23. for (i = ; i < (sizeof(_core_dump_signals) / sizeof((_core_dump_signals)[])); i++)
  24. sigaction(_core_dump_signals[i], &act, NULL);
  25. /* unblock all the signals, because if the current process is
  26. * spawned in the previous signal handler, all the signals are
  27. * blocked. In order to make it sense of signals, we should
  28. * unblock them. Certainly, you should call this function as
  29. * early as possible. :) */
  30. sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL);
  31.  
  32. //sigemptyset(&myAction.sa_mask);
  33. //myAction.sa_flags = SA_RESTART | SA_SIGINFO;
  34. //LOG(LOGLV_WARN, "Log::installTrace!!!\n");
  35. }
  36. //#include <sys/wait.h>
  37. ////等待fok的子进程信号,防止僵尸进程
  38. //void fok_chld_wait(int signo) {
  39. // pid_t pid;
  40. // int stat;
  41. // while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
  42. // printf("child %d exit\n", pid);
  43. // }
  44. // return;
  45. //}
  46. ////设置等待fok的子进程信号
  47. //int set_fok_chld_wait_signal() {
  48. // struct sigaction act, oact;
  49. // act.sa_handler = fok_chld_wait;
  50. // sigemptyset(&act.sa_mask);
  51. // act.sa_flags = 0;
  52. //
  53. // if (sigaction(SIGCHLD, &act, &oact) < 0) {
  54. // return -1;
  55. // }
  56. // return 0;
  57. //}
  58. //重新启动进程
  59. static void _restart(void)
  60. {
  61. char buf[];
  62. char exe[];
  63. char **argv;
  64. int fd, len;
  65. size_t argv_size, i;
  66. char *ptr, *ptr_end;
  67. struct rlimit limit;
  68.  
  69. /* find the file executable. */
  70. len = readlink("/proc/self/exe", exe, sizeof(exe) - );
  71. if (len == - || len == sizeof(exe) - )
  72. _exit(EXIT_FAILURE);
  73. exe[len] = '\0';
  74.  
  75. /* generate the variable argv. */
  76. fd = open("/proc/self/cmdline", O_RDONLY);
  77. if (fd == -)
  78. _exit(EXIT_FAILURE);
  79. len = read(fd, buf, sizeof(buf));
  80. if (len == - || len == sizeof(buf))
  81. _exit(EXIT_FAILURE);
  82. buf[len] = '\0';
  83. argv_size = ;
  84. argv = (char**)malloc(sizeof(char*) * argv_size);
  85. if (argv == NULL)
  86. _exit(EXIT_FAILURE);
  87. for (i = , ptr = buf, ptr_end = buf + len;
  88. ptr < ptr_end; i++, ptr += strlen(ptr) + ) {
  89. if (i >= argv_size - ) {
  90. argv_size <<= ;
  91. argv = (char**)realloc(argv, sizeof(char*) * argv_size);
  92. if (argv == NULL)
  93. _exit(EXIT_FAILURE);
  94. }
  95. argv[i] = ptr;
  96. }
  97. argv[i] = NULL;
  98.  
  99. /* close all the file descriptors except of stdin/stdout/stderr. */
  100. getrlimit(RLIMIT_NOFILE, &limit);
  101. for (i = ; i < limit.rlim_cur; i++)
  102. close(i);
  103.  
  104. execvp(exe, argv);
  105.  
  106. /* exit if it fails to restart self. */
  107. _exit(EXIT_FAILURE);
  108. }
  109. //打印当前线程的函数调用堆栈
  110. void LogTrace(int signo)
  111. {
  112. //set_fok_chld_wait_signal();
  113. //父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,
  114. //那么子进程结束后,内核会回收, 并不再给父进程发送信号。
  115. //或用sigaction函数为SIGCHLD设置SA_NOCLDWAIT,这样子进程结束后,就不会进入僵死状态
  116. struct sigaction sa;
  117. sa.sa_handler = SIG_IGN;
  118. sa.sa_flags = SA_NOCLDWAIT;
  119. sigemptyset(&sa.sa_mask);
  120. sigaction(SIGCHLD, &sa, NULL);
  121.  
  122. void *callstacks[];
  123. if (!_pLogFile)
  124. Log.ChangeFile();
  125.  
  126. if (_pLogFile)
  127. {
  128. std::lock_guard<std::mutex> lock{ _csLog };
  129. struct timeval tv;
  130. struct tm *p;
  131. gettimeofday(&tv, NULL);
  132. p = localtime(&tv.tv_sec);
  133.  
  134. size_t size = sizeof(callstacks);
  135. int fd = fileno(_pLogFile);
  136. fprintf(_pLogFile, "-----------------------------------0 SIG=%d-%s err=%d-%s tid=%d %d-%02d-%02d %02d:%02d:%02d.%06d\n"
  137. , signo, strsignal(signo), errno, strerror(errno), gettid(), p->tm_year + , p->tm_mon + , p->tm_mday, p->tm_hour, p->tm_min, (int)p->tm_sec, (int)tv.tv_usec );
  138. fflush(_pLogFile);
  139. size = backtrace(callstacks, size);
  140. backtrace_symbols_fd(callstacks, size, fd);
  141. fprintf(_pLogFile, "-----------------------------------1 callstack=20/%d\n", (int)size);
  142. fflush(_pLogFile);
  143. //定位源代码行
  144. char cmd[] = "addr2line -f -e ";
  145. char buff1[] = { }, buff2[] = { }, buff3[] = { };
  146. char* prog = cmd + ;
  147. readlink("/proc/self/exe", prog, );// 获取进程的完整路径
  148. int leftlen = strlen(cmd);
  149. prog = cmd + leftlen;
  150. leftlen = - leftlen;
  151. for (size_t i = ; i < size; ++i)
  152. {
  153. snprintf(prog, leftlen, " %p\n", callstacks[i]);
  154. FILE* fp = popen(cmd, "r");
  155. if (fp != NULL)
  156. {
  157. if (NULL != fgets(buff1, , fp))
  158. {
  159. fgets(buff2, , fp);
  160. if (buff2[strlen(buff2) - ] == '\n')
  161. buff2[strlen(buff2) - ] = ;
  162. snprintf(buff3, , "c++filt %s\n", buff1);//用c++filt 使函数名可视化
  163. FILE* fp2 = popen(buff3, "r");
  164. if (fp2 && fgets(buff3, , fp2)) {
  165. fprintf(_pLogFile, ">%s %s", buff2, buff3);
  166. pclose(fp2);
  167. }
  168. else
  169. fprintf(_pLogFile, ">%s %s", buff2, buff1);
  170. }
  171. pclose(fp);
  172. }
  173. }
  174. fprintf(_pLogFile, "-----------------------------------2 end\n");
  175. fflush(_pLogFile);
  176. }
  177.  
  178. //core dump
  179. pid_t pid = fork();
  180. if (pid == ) {
  181. #ifdef _FORCE_CORE_DUMP
  182. #ifndef _CORE_SIZE
  183. #define _CORE_SIZE (256 * 1024 * 1024)
  184. #endif /* _CORE_SIZE */
  185. struct rlimit limit = {
  186. .rlim_cur = _CORE_SIZE,
  187. .rlim_max = _CORE_SIZE };
  188.  
  189. setrlimit(RLIMIT_CORE, &limit);
  190. #endif /* _FORCE_CORE_DUMP */
  191. /* reset the signal handler to default handler,
  192. * then raise the corresponding signal. */
  193. signal(signo, SIG_DFL);
  194. raise(signo);
  195. _exit(EXIT_FAILURE);
  196. }
  197. else
  198. _restart();//自动重启
  199. }
  200. /* const char* sigstr[] = {
  201. "01 SIGHUP 挂起(hangup)",
  202. "02 SIGINT 中断,当用户从键盘按^c键或^break键时",
  203. "03 SIGQUIT 退出,当用户从键盘按quit键时",
  204. "04 SIGILL 非法指令",
  205. "05 SIGTRAP 跟踪陷阱(trace trap),启动进程,跟踪代码的执行",
  206. "06 SIGIOT IOT指令",
  207. "07 SIGEMT EMT指令",
  208. "08 SIGFPE 浮点运算溢出",
  209. "09 SIGKILL 杀死、终止进程 ",
  210. "10 SIGBUS 总线错误",
  211. "11 SIGSEGV 段违例(segmentation violation),进程试图去访问其虚地址空间以外的位置",
  212. "12 SIGSYS 系统调用中参数错,如系统调用号非法",
  213. "13 SIGPIPE 向某个非读管道中写入数据",
  214. "14 SIGALRM 闹钟。当某进程希望在某时间后接收信号时发此信号",
  215. "15 SIGTERM 软件终止(software termination)",
  216. "16 SIGUSR1 用户自定义信号1",
  217. "17 SIGUSR2 用户自定义信号2",
  218. "18 SIGCLD 某个子进程死",
  219. "19 SIGPWR 电源故障"
  220. };*/
  221.  
  222. //设置线程优先级(设置为普通优先级)
  223. //参数为线程句柄,或 std::thread::native_handle()
  224. void SetThrPriorityNormal(void* handle)
  225. {
  226. sched_param sch;
  227. int policy, policy2;
  228. pthread_getschedparam(handle, &policy, &sch);
  229. sch.sched_priority = ;
  230. if (pthread_setschedparam(handle, SCHED_FIFO, &sch))
  231. LOG(LOGLV_NOTICE, "Failed to setschedparam normal: %s \n", std::strerror(errno));
  232. pthread_getschedparam(handle, &policy2, &sch);
  233. LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", policy, policy2);
  234. }
  235. //设置线程优先级(设置为高(HIGHEST)优先级)
  236. //参数为线程句柄,或 std::thread::native_handle()
  237. void SetThrPriorityHighst(void* handle)
  238. {
  239. sched_param sch;
  240. int policy, policy2;
  241. pthread_getschedparam(handle, &policy, &sch);
  242. sch.sched_priority = -;
  243. if (pthread_setschedparam(handle, SCHED_FIFO, &sch))
  244. LOG(LOGLV_NOTICE, "Failed to setschedparam normal: %s \n", std::strerror(errno));
  245. pthread_getschedparam(handle, &policy2, &sch);
  246. LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", policy, policy2);
  247. }

这些也是网上搜别人的代码,然后自己修改了的,可以直接运。

编译时,要加参数 -g 。或者加 -g3 -ggdb -gstabs。

2. win获取崩溃类型和生成dump文件

代码奉上:
  1. //Dump调试
  2. #include <DbgHelp.h>
  3. #include <shellapi.h>
  4.  
  5. typedef BOOL(*MINIDUMPWRITEDUMP)(HANDLE hProcess,
  6. DWORD ProcessId,
  7. HANDLE hFile,
  8. MINIDUMP_TYPE DumpType,
  9. PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
  10. PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
  11. PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
  12.  
  13. MINIDUMPWRITEDUMP pDumpFunc = NULL; // 声明函数指针
  14. const char* seh_filer(DWORD code)
  15. {
  16. switch (code)
  17. {
  18. case EXCEPTION_ACCESS_VIOLATION:
  19. return ("存储保护异常(解空指针)");
  20. case EXCEPTION_DATATYPE_MISALIGNMENT:
  21. return ("数据类型未对齐异常");
  22. case EXCEPTION_BREAKPOINT:
  23. return ("中断异常");
  24. case EXCEPTION_SINGLE_STEP:
  25. return ("单步中断异常");
  26. case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  27. return ("数组越界异常");
  28. case EXCEPTION_FLT_DENORMAL_OPERAND:
  29. case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  30. case EXCEPTION_FLT_INEXACT_RESULT:
  31. case EXCEPTION_FLT_INVALID_OPERATION:
  32. case EXCEPTION_FLT_OVERFLOW:
  33. case EXCEPTION_FLT_STACK_CHECK:
  34. case EXCEPTION_FLT_UNDERFLOW:
  35. return ("浮点数计算异常");
  36. case EXCEPTION_INT_DIVIDE_BY_ZERO:
  37. return ("被0除异常");
  38. case EXCEPTION_INT_OVERFLOW:
  39. return ("数据溢出异常");
  40. case EXCEPTION_IN_PAGE_ERROR:
  41. return ("页错误异常");
  42. case EXCEPTION_ILLEGAL_INSTRUCTION:
  43. return ("非法指令异常");
  44. case EXCEPTION_STACK_OVERFLOW:
  45. return ("堆栈溢出异常");
  46. case EXCEPTION_INVALID_HANDLE:
  47. return ("无效句柄异常");
  48. default:
  49. if (code & ( << ))
  50. return ("用户自定义的软件异常");
  51. else
  52. return ("其它异常");
  53. }
  54. }
  55. // 参数lpExceptionInfo包含了异常信息,由系统提供
  56. LONG WINAPI ExceptionFilterFunc(struct _EXCEPTION_POINTERS* lpExceptionInfo)
  57. {
  58. //if(pDumpFunc==NULL) return -1;
  59.  
  60. LONG ret = EXCEPTION_CONTINUE_SEARCH;
  61. // 根据当前线程ID,时间创建dmp文件
  62. int irand = rand() % ;
  63. char strFile[];
  64. SYSTEMTIME st;
  65. DWORD ul = lpExceptionInfo->ExceptionRecord->ExceptionCode;
  66. LOG(LOGLV_CRIT, "exception %X,%s\n", ul, seh_filer(ul));
  67. GetLocalTime(&st);
  68. ::CreateDirectory("dumps\\", NULL);
  69. _snprintf_s(strFile, , "dumps\\DMP-%d_%04d%02d%02d_%02d%02d%02d.%03d_%04d.dmp", ::GetCurrentThreadId(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, irand);
  70. HANDLE hFile = ::CreateFile(strFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  71. if (hFile != INVALID_HANDLE_VALUE)
  72. {
  73. MINIDUMP_EXCEPTION_INFORMATION ExInfo;
  74. ExInfo.ThreadId = ::GetCurrentThreadId();
  75. ExInfo.ExceptionPointers = lpExceptionInfo;
  76. ExInfo.ClientPointers = NULL;
  77. MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(//MiniDumpWithFullMemory |
  78. MiniDumpWithHandleData | MiniDumpFilterModulePaths |
  79. MiniDumpWithProcessThreadData |
  80. MiniDumpWithIndirectlyReferencedMemory |
  81. MiniDumpWithPrivateReadWriteMemory |
  82. MiniDumpWithFullMemoryInfo |
  83. MiniDumpWithUnloadedModules |
  84. //MiniDumpWithDataSegs |
  85. MiniDumpWithThreadInfo );
  86.  
  87. //加载DebugDump函数 //MiniDumpWriteDump 函数在头文件(DbgHelp.h)中有定义
  88. HMODULE hDll = LoadLibrary("dbghelp.dll");
  89. if (hDll == NULL)
  90. LOG(LOGLV_ALERT, "Error: load dbghelp.dll fail\n\n");
  91. else
  92. {
  93. //load MiniDumpWriteDump function
  94. pDumpFunc = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
  95. if (pDumpFunc == NULL)
  96. LOG(LOGLV_ALERT, "Error: load MiniDumpWriteDump function fail\n\n");
  97. else {
  98. //将崩溃信息记录到dmp文件中
  99. BOOL bRet = pDumpFunc(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, &ExInfo, NULL, NULL);
  100. if (bRet) {
  101. ret = EXCEPTION_EXECUTE_HANDLER;
  102. LOG(LOGLV_WARN, "DumpFile: %s\n", strFile);
  103. }
  104. else
  105. LOG(LOGLV_CRIT, "call MiniDumpWriteDump fail...\n");
  106. }
  107. //卸载 dbghelp.dll
  108. if (hDll != NULL)
  109. FreeLibrary(hDll);
  110. }
  111. ::CloseHandle(hFile);
  112. }
  113. else
  114. LOG(LOGLV_CRIT, "CreateFile fail... %s\n", strFile);
  115. char *fullpth;
  116. _get_pgmptr(&fullpth);
  117. char* cmdl = strstr(GetCommandLine(), ".exe ");
  118. ShellExecute(NULL, "open", fullpth, (cmdl ? (cmdl + ) : nullptr), Log.CurPath(), SW_SHOW);
  119. return ret;
  120. }
  121.  
  122. //安装崩溃时//打印当前线程的函数调用堆栈
  123. //该流程只对本线程有效,如果是多线程,需要对每个线程都做调用处理。
  124. void installTrace() {
  125. // 设置异常捕获函数
  126. ::SetUnhandledExceptionFilter(ExceptionFilterFunc);
  127. }
  128.  
  129. //设置线程优先级(设置为普通优先级)
  130. ////如果进程的优先级为最高,则降低2级
  131. //参数为线程句柄,或 std::thread::native_handle()
  132. void SetThrPriorityNormal(void* handle)
  133. {
  134. int r0 = GetThreadPriority(handle);
  135. int r = ;
  136. //int p = GetPriorityClass(GetCurrentProcess());
  137. //if (p > 100)//如果进程的优先级为最高,则降低2级
  138. // r = -2;
  139. int r1 = SetThreadPriority(handle, r);
  140. r1 = GetThreadPriority(handle);
  141. LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", r0, r1);
  142. }
  143. //设置线程优先级(设置为高(HIGHEST)优先级)
  144. //参数为线程句柄,或 std::thread::native_handle()
  145. void SetThrPriorityHighst(void* handle)
  146. {
  147. int r0 = GetThreadPriority(handle);
  148. int r1 = SetThreadPriority(handle, THREAD_PRIORITY_HIGHEST);
  149. r1 = GetThreadPriority(handle);
  150. LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", r0, r1);
  151. }

网上搜索,说是 win有办法可以获取崩溃的函数和类名,但是比较复杂,就没有搞了。

3. 使用方式
在线程开始处调用 installTrace 安装异常捕获即可。
注意:每条线程都安装,如果要捕获未处理异常的话。

获取崩溃时的调用栈和生成dump文件,然后自动重启的更多相关文章

  1. [转]让程序在崩溃时体面的退出之SEH+Dump文件

    原文地址:http://blog.csdn.net/starlee/article/details/6649605 在我上篇文章<让程序在崩溃时体面的退出之SEH>中讲解了SEH中try/ ...

  2. 如何设置C++崩溃时生成Dump文件

    Dump 文件是进程的内存镜像 , 可以把程序的执行状态通过调试器保存到dump文件中 ; Dump 文件是用来给驱动程序编写人员调试驱动程序用的 , 这种文件必须用专用工具软件打开 , 比如使用 W ...

  3. JVM在遇到OOM(OutOfMemoryError)时生成Dump文件

    方法一: 命令:jmap -dump:format=b,file=heap.bin file:保存路径及文件名pid:进程编号(windows通过任务管理器查看,linux通过ps aux查看) du ...

  4. 程序自动生成Dump文件

    前言:通过drwtsn32.NTSD.CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD.CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD.CDB等调试工具.了解了 ...

  5. 程序自动生成Dump文件()

    前言:通过drwtsn32.NTSD.CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD.CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD.CDB等调试工具.了解了 ...

  6. 调试SQLSERVER (一)生成dump文件的方法

    调试SQLSERVER (一)生成dump文件的方法 调试SQLSERVER (二)使用Windbg调试SQLSERVER的环境设置调试SQLSERVER (三)使用Windbg调试SQLSERVER ...

  7. 使用dbghelp生成dump文件以及事后调试分析

    前言 在产品的实际应用环境中,如果我们的程序在客户那里出现了问题,例如程序异常了,而这个时候的现象又不能还原或者很难还原重现,那么只有使用dump文件来保存程序的当前运行信息,例如调用堆栈等,同时使用 ...

  8. 如何生成Dump文件

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:如何生成Dump文件.

  9. 使用ProcDump自动生成Dump文件

    ProcDump工具来自Sysinternals Suite 最近用来自动产生Dump文件 一是用来监视服务器程序无响应 procdump -accepteula -64 -ma -h server. ...

随机推荐

  1. css animation动画

    css 动画: 动画是CSS3中具有颠覆性的特征之一,可通过设置多个节点来精确控制一个或一组动画,常用来实现复杂的动画效果. 必要元素: a.通过@keyframes指定动画序列:自动补间动画,确定两 ...

  2. Ambari HDP集群搭建文档

    一.配置主机和节点机器之间SSH无密登录 多台外网服务器配置时,需要在/etc/hosts中把本机的IP地址设置为内网IP地址 http://2d67df38.wiz02.com/share/s/0J ...

  3. WPF 使用MahApps.Metro UI库

    在WPF中要想使用Metro风格是很简单的,可以自己画嘛.. 但是为了节省时间,哈,今天给大家推荐一款国外Metro风格的控件库. 本文只起到抛砖引玉的作用,有兴趣还是推荐大家上官网,Thanks,官 ...

  4. Jitsi 开源视频会议远程桌面共享&&文档共享工具

    1. 特点 主要功能特点: 支持网络视频会议,使用SFU模式实现视频路由器功能. 支持SIP帐号注册电话呼叫. 支持安卓苹果终端. 支持文档共享功能,即时消息功能. 支持中文界面. 支持会议邀请,密码 ...

  5. warning: backslash and newline separated by space [enabled by default]

    警告:反斜杠和换行符之间多了空格. 这种问题出现在宏定义 #define,并且有多行,每行之间要用 “\” 连接起来. 解决办法:删除 “\” 后面的空格,直接紧跟回车.

  6. ThinkPHP 分页功能梳理

    最近在开发一个项目,使用了国内流行的ThinkPHP框架,我之前没怎么用过这个框架,也是临时抱佛脚,用的不怎么样?可能理解不是很深刻,如果有说的不对或不正确的地方,请大家多包涵,多指教. ThinkP ...

  7. 配置Jar包及相关依赖Jar包的本地存放路径

    配置Jar包及相关依赖Jar包的本地存放路径 用 maven2 ,pom.xml中设置了依赖,会帮你下载所有依赖的.jar到 M2_REPO 指向的目录. M2_REPO是一个用来定义 maven 2 ...

  8. FPGA的CNN加速,你怎么看?

    网上对于FPGACNN加速的研究已经很多了,神经网络的硬件加速似乎已经满大街都是了,这里我们暂且不讨论谁做的好谁做的不好,我们只是根据许许多多的经验来总结一下实现硬件加速,需要哪些知识,考虑哪些因素. ...

  9. Firewalld防火墙与ICMP攻击

    原文地址:http://www.excelib.com/article/293/show 提到ICMP大家应该都很熟悉,可能有人会说:不就是ping吗?但是说到ICMP攻击以及相关防御措施可能就有的人 ...

  10. python 面向对象(其他相关)

    python 面向对象(其他相关): (思维导图    ↑↑↑↑↑↑) 一.issubclass(obj,cls) 检查obj是否是类cls的对象 class Base(object): pass c ...