轉自:http://www.cnblogs.com/zhy113/archive/2013/03/15/2960910.html
家在寫server的時候,不管server寫的是多麼健壯,還是經常出現core dump等程式異常退出的,但是一般情況下需要在無人為幹預情況下,能夠自動重新啟動,保證server程式能夠服務使用者。這時就需要一個監控程式來實現 能夠讓程式自動重新啟動,現在筆者在寫portmap就遇到了這個問題,通過網上尋找資料,找到了一個相對靠譜的exec+fork解決方案。
使用指令碼實現自動重啟
首先想到的最簡單的使用shell指令碼,大概思路:
ps -ef | grep “$1″ | grep -v “grep” | wc –l 是擷取 $1 ($1 代表進程的名字)的進程數,指令碼根據進程數來決定下一步的操作。通過一個死迴圈,每隔 1 秒檢查一次系統中的指定程式的進程數,這裡也可使用crontab來實現。
這種方法比較土,還是可以基本解決問題,但是有1s的延遲,筆者在應用中未採用這種方法,有關這個shell指令碼,請參看文章後面的附件代碼。
exec+fork方式
筆者最終採用的exec+fork方式來實現的,具體思想如下:
1,exec函數把當前進程替換為一個新的進程,新進程由path或file參數指定。可以使用exec函數將程式的執行從一個程式切換到另一個程式;
2,fork函數是建立一個新的進程,在進程表中建立一個新的表項,而建立者(即父進程)按原來的流程繼續執行,子進程執行自己的控制流程程;
3,wait 當fork啟動一個子進程時,子進程就有了它自己的生命週期並將獨立運行,我們可以在父進程中調用wait函數讓父進程等待子進程的結束;
相信介紹到這裡,讀者已經能夠想到解決方案了:1)首先使用fork系統調用,建立子進程,2)在子進程中使用exec函數,執行需要自動重啟的程式,3) 在父進程中執行wait等待子進程的結束,然後重新建立一個新的子進程。
使用方法:
#./portmap 需要監控的程式的路徑#args portmap 需要的參數$ ./supervisor ./portmap args.....
代碼如下:
/** * * supervisor * * author: liyangguang (liyangguang@software.ict.ac.cn) * * date: 2011-01-21 21:04:01 * * changes * 1, execl to execv */#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/wait.h>#include <stdlib.h>int main(int argc, char **argv){ int ret, i, status; char *child_argv[100] = {0}; pid_t pid; if (argc < 2) { fprintf(stderr, "Usage:%s <exe_path> <args...><strong>n</strong>", argv[0]); return -1; } for (i = 1; i < argc; ++i) { child_argv[i-1] = (char *)malloc(strlen(argv[i])+1); strncpy(child_argv[i-1], argv[i], strlen(argv[i])); child_argv[i-1][strlen(argv[i])] = '<strong>0</strong>'; } while(1){ pid = fork(); if (pid == -1) { fprintf(stderr, "fork() error.errno:%d error:%s<strong>n</strong>", errno, strerror(errno)); } if (pid == 0) { ret = execv(child_argv[0], (char **)child_argv); if (ret < 0) { fprintf(stderr, "execv ret:%d errno:%d error:%s<strong>n</strong>", ret, errno, strerror(errno)); continue; } exit(0); }if (pid > 0) { pid = wait(&status); fprintf(stdout, "wait return"); } }return 0;}
shell指令碼方式的代碼如下:
# 函數: CheckProcess# 功能: 檢查一個進程是否存在# 參數: $1 --- 要檢查的進程名稱# 返回: 如果存在返回0, 否則返回1.#------------------------------------------------------------------------------CheckProcess(){ # 檢查輸入的參數是否有效 if [ "$1" = "" ]; then return 1 fi #$PROCESS_NUM擷取指定進程名的數目,為1返回0,表示正常,不為1返回1,表示有錯誤,需要重新啟動 PROCESS_NUM=`ps -ef | grep "$1" | grep -v "grep" | wc -l` if [ $PROCESS_NUM -eq 1 ]; then return 0 else return 1 fi} # 檢查test執行個體是否已經存在while [ 1 ] ; do CheckProcess "test" CheckQQ_RET=$? if [ $CheckQQ_RET -eq 1 ]; then # 殺死所有test進程,可換任意你需要執行的操作 killall -9 test exec ./test & fi sleep 1done
轉自:http://www.cnblogs.com/zhy113/archive/2013/03/15/2960910.html
家在寫server的時候,不管server寫的是多麼健壯,還是經常出現core dump等程式異常退出的,但是一般情況下需要在無人為幹預情況下,能夠自動重新啟動,保證server程式能夠服務使用者。這時就需要一個監控程式來實現 能夠讓程式自動重新啟動,現在筆者在寫portmap就遇到了這個問題,通過網上尋找資料,找到了一個相對靠譜的exec+fork解決方案。
使用指令碼實現自動重啟
首先想到的最簡單的使用shell指令碼,大概思路:
ps -ef | grep “$1″ | grep -v “grep” | wc –l 是擷取 $1 ($1 代表進程的名字)的進程數,指令碼根據進程數來決定下一步的操作。通過一個死迴圈,每隔 1 秒檢查一次系統中的指定程式的進程數,這裡也可使用crontab來實現。
這種方法比較土,還是可以基本解決問題,但是有1s的延遲,筆者在應用中未採用這種方法,有關這個shell指令碼,請參看文章後面的附件代碼。
exec+fork方式
筆者最終採用的exec+fork方式來實現的,具體思想如下:
1,exec函數把當前進程替換為一個新的進程,新進程由path或file參數指定。可以使用exec函數將程式的執行從一個程式切換到另一個程式;
2,fork函數是建立一個新的進程,在進程表中建立一個新的表項,而建立者(即父進程)按原來的流程繼續執行,子進程執行自己的控制流程程;
3,wait 當fork啟動一個子進程時,子進程就有了它自己的生命週期並將獨立運行,我們可以在父進程中調用wait函數讓父進程等待子進程的結束;
相信介紹到這裡,讀者已經能夠想到解決方案了:1)首先使用fork系統調用,建立子進程,2)在子進程中使用exec函數,執行需要自動重啟的程式,3) 在父進程中執行wait等待子進程的結束,然後重新建立一個新的子進程。
使用方法:
#./portmap 需要監控的程式的路徑#args portmap 需要的參數$ ./supervisor ./portmap args.....
代碼如下:
/** * * supervisor * * author: liyangguang (liyangguang@software.ict.ac.cn) * * date: 2011-01-21 21:04:01 * * changes * 1, execl to execv */#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/wait.h>#include <stdlib.h>int main(int argc, char **argv){ int ret, i, status; char *child_argv[100] = {0}; pid_t pid; if (argc < 2) { fprintf(stderr, "Usage:%s <exe_path> <args...><strong>n</strong>", argv[0]); return -1; } for (i = 1; i < argc; ++i) { child_argv[i-1] = (char *)malloc(strlen(argv[i])+1); strncpy(child_argv[i-1], argv[i], strlen(argv[i])); child_argv[i-1][strlen(argv[i])] = '<strong>0</strong>'; } while(1){ pid = fork(); if (pid == -1) { fprintf(stderr, "fork() error.errno:%d error:%s<strong>n</strong>", errno, strerror(errno)); } if (pid == 0) { ret = execv(child_argv[0], (char **)child_argv); if (ret < 0) { fprintf(stderr, "execv ret:%d errno:%d error:%s<strong>n</strong>", ret, errno, strerror(errno)); continue; } exit(0); }if (pid > 0) { pid = wait(&status); fprintf(stdout, "wait return"); } }return 0;}
shell指令碼方式的代碼如下:
# 函數: CheckProcess# 功能: 檢查一個進程是否存在# 參數: $1 --- 要檢查的進程名稱# 返回: 如果存在返回0, 否則返回1.#------------------------------------------------------------------------------CheckProcess(){ # 檢查輸入的參數是否有效 if [ "$1" = "" ]; then return 1 fi #$PROCESS_NUM擷取指定進程名的數目,為1返回0,表示正常,不為1返回1,表示有錯誤,需要重新啟動 PROCESS_NUM=`ps -ef | grep "$1" | grep -v "grep" | wc -l` if [ $PROCESS_NUM -eq 1 ]; then return 0 else return 1 fi} # 檢查test執行個體是否已經存在while [ 1 ] ; do CheckProcess "test" CheckQQ_RET=$? if [ $CheckQQ_RET -eq 1 ]; then # 殺死所有test進程,可換任意你需要執行的操作 killall -9 test exec ./test & fi sleep 1done