因爲UNP第三部分(第三版13-31章)的內容結合APUE(UNIX環境高級編程)和TLPI(The Linux Programming Interface)來看才能比較清晰,所以筆記整理會穿插很多這兩本書的內容
13章
- 13.4節:自定義一個daemon_init函數,涉及到知識點爲“如何創建一個daemon(守護進程)”,實現步驟如下:
- fork之後殺掉父進程(此時子進程被init收養)這是爲了爲下一步setsid做準備,因爲只有不是進程組首進程的進程才能調用setsid,
- setsid,創建一個新的會話並斷開與之前的控制終端的關係,
- 再次fork並殺掉首進程, 這樣就確保了子進程不是一個會話首進程, 根據linux中獲取終端的規則(只有會話首進程才能請求一個控制終端), 這樣進程永遠不會重新請求一個控制終端
- 清楚進程的umask,確保daemon創建文件和目錄時擁有相應的權限
- 修改進程的當前工作目錄, 通常修改到/目錄
- 關閉進程所有不再需要的文件描述符
- 打開/dev/null使文件描述符0、1、2指向這個設備, 以防止daemon調用在這些描述符上做I/O操作的庫函數而不會意外的失敗
#include "unp.h"
#include <syslog.h>
#define MAXFD 64
extern int daemon_proc; /* defined in error.c */
int
daemon_init(const char *pname, int facility)
{
int i;
pid_t pid;
if ( (pid = Fork()) < 0)
return (-1);
else if (pid)
_exit(0); /* parent terminates */
/* child 1 continues... */
if (setsid() < 0) /* become session leader */
return (-1);
Signal(SIGHUP, SIG_IGN);
if ( (pid = Fork()) < 0)
return (-1);
else if (pid)
_exit(0); /* child 1 terminates */
/* child 2 continues... */
daemon_proc = 1; /* for err_XXX() functions */
chdir("/"); /* change working directory */
/* close off file descriptors */
for (i = 0; i < MAXFD; i++)
close(i);
/* redirect stdin, stdout, and stderr to /dev/null */
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
openlog(pname, LOG_PID, facility);
return (0); /* success */
}
引申知識,作業控制以及相關命令:
- 另注:
注:但是如上方到後臺執行的進程,其父進程還是當前終端shell的進程,而一旦父進程退出,則會發送hangup信號給所有子進程,子進程收到hangup以後也會退出。
nohup和setsid用法
如果我們要在退出shell的時候繼續運行進程,則需要使用nohup忽略hangup信號,或者setsid將父進程設爲init進程;
b@b-VirtualBox:~/my_temp_test$ nohup ./o_multi_thread_process &
[1] 3487
b@b-VirtualBox:~/my_temp_test$ nohup: ignoring input and appending output to ‘nohup.out’
^C
b@b-VirtualBox:~/my_temp_test$ jobs
[1]+ Running nohup ./o_multi_thread_process &
b@b-VirtualBox:~/my_temp_test$ ps -ef | grep multi
b 3487 3004 0 20:05 pts/3 00:00:00 ./o_multi_thread_process
b 3488 3487 0 20:05 pts/3 00:00:00 ./o_multi_thread_process
b 3491 3004 0 20:05 pts/3 00:00:00 grep --color=auto multi
b@b-VirtualBox:~/my_temp_test$ bg %1
bash: bg: job 1 already in background
b@b-VirtualBox:~/my_temp_test$ fg %1
nohup ./o_multi_thread_process
^Z
[1]+ Stopped nohup ./o_multi_thread_process
b@b-VirtualBox:~/my_temp_test$ bg %1
[1]+ nohup ./o_multi_thread_process &
b@b-VirtualBox:~/my_temp_test$ jobs -l
[1]+ 3487 Running nohup ./o_multi_thread_process &
b@b-VirtualBox:~/my_temp_test$ fg %1
nohup ./o_multi_thread_process
^C
b@b-VirtualBox:~/my_temp_test$ jobs
b@b-VirtualBox:~/my_temp_test$ ps -ef | grep multi
b 3499 3004 0 20:11 pts/3 00:00:00 grep --color=auto multi
b@b-VirtualBox:~/my_temp_test$ setsid ./o_multi_thread_process &
[1] 3502
b@b-VirtualBox:~/my_temp_test$ ProcessA: 3503 step1
ProcessA: 3503 thread 139947724490496 step2
ProcessA: 3503 thread 139947724490496 step3
ProcessB: 3504 step1
ProcessB: 3504 step2
ProcessB: 3504 step3
^C
[1]+ Done setsid ./o_multi_thread_process
b@b-VirtualBox:~/my_temp_test$ ps -ef | grep multi
b 3503 1256 0 20:12 ? 00:00:00 ./o_multi_thread_process
b 3504 3503 0 20:12 ? 00:00:00 ./o_multi_thread_process
b 3507 3004 0 20:12 pts/3 00:00:00 grep --color=auto multi
b@b-VirtualBox:~/my_temp_test$ jobs
disown用法
那麼對於已經在後臺運行的進程,該怎麼辦呢?可以使用disown命令
b@b-VirtualBox:~/my_temp_test$ ./o_multi_thread_process &
[1] 3523
b@b-VirtualBox:~/my_temp_test$ ProcessA: 3523 step1
ProcessA: 3523 thread 140501901821696 step2
ProcessA: 3523 thread 140501901821696 step3
ProcessB: 3524 step1
ProcessB: 3524 step2
ProcessB: 3524 step3
^C
b@b-VirtualBox:~/my_temp_test$ jobs -l
[1]+ 3523 Running ./o_multi_thread_process &
b@b-VirtualBox:~/my_temp_test$ disown -h %1
b@b-VirtualBox:~/my_temp_test$ jobs
[1]+ Running ./o_multi_thread_process &
16章
16.3節 : 非阻塞connect
- 有三個用途:
- 我們想在connect的時候處理其他事情
- 可以同時建立多個連接
- 可以通過select設置一個更短一點的超時時間
- 實現步驟:
- 用fcntl把套接字設置爲非阻塞
- 處理客戶端和服務器都在同一主機上的情況
- 使用select設置超時,並處理超時情況
- 處理當連接建立的時候,描述符變爲可寫;以及當連接建立遇到錯誤的時候, 描述符變爲可寫並可讀的情況
- 有三個用途:
16.6節 : 非阻塞accept,
用於解決下面問題:
“用select檢測socket狀態,如果有連接就調用accept,這樣如果在select檢測到由連接請求,在調用accept之前,這個請求斷開了,然後調用accept的時候就會阻塞在哪裏,除非這時有另外一個連接請求,如果沒有,則一直被阻塞在那裏。”
解決方案:
使用select在一個監聽套接字準備好要被accept時總是把套接字設置爲非阻塞
26章和30章
介紹了線程和併發/並行的服務器設計範式,等下篇TLPI/APUE的筆記一起整理吧