早上5點不到爬起床,現在8點多。
在整理下一個階段的內容,CGI/FASTCGI, 這些早期的老掉牙技術,因為當紅的web framework ROR (RUBY ON RAILS)採用FASTCGI,又重新讓人注意。
在mini web server中,有一個德國人,http://towiski.de/software.html寫的支援CGI 的程式,引起我的注意。
有了之前累積的經驗,應該如法泡製,而且他的寫法和獵豹某些結構上,命名方式,有些異曲同工的地方。3小時後,筆者發現,看code,和trace code,不一樣。
web server 基本上都有一個主迴圈hold住,在listen 來自browser的requset,
以 mattows為例(下載網址:http://towiski.de/binaries/mattows-1.8.tar.bz2)
是這樣寫:
while(1) {
int pid;
socklen_t peerlen=sizeof(peer);
mywarn("Waiting for connections on port %d\n",ntohs(port));
as = accept(sock,(struct sockaddr*)&peer,&peerlen);
if(-1 == as) {
if(EINTR != errno)
mywarn("accept: %s\n",strerror(errno));
continue;
}
switch(pid = fork()) {
case -1 :
mywarn("error forking connection handler: %s\n",strerror(errno));
break;
case 0 :
close(sock);
mywarn("Accepted connection from %s:%d\n",
inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
exit(handle_connection(as,&peer));
default :
close(as);
}
}
看得出來,handle_connection是我們關注的點。看了code,也如我們相像的。 把中斷點,下在這裏。b handle_connection
做了N次,每次都過站不停。
我想,怪怪的,那我停在
switch(pid = fork(),
我發現一個更奇異的現象,
它每次的跑法,
switch(pid = fork()) {
case -1 :
mywarn("error forking connection handler: %s\n",strerror(errno));
break;
case 0 :
close(sock);
mywarn("Accepted connection from %s:%d\n",
inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
exit(handle_connection(as,&peer));
default :
close(as);
}
都直接跑到 default:
可是從它show在console的訊息,它明明有跑選項case 0 :,這個case也一直過站不停。
但是雖然我的C語言再不行,但是也有看過邦友在LINUX相關的分享,
行程的ID, 要0的機會有可能嗎??可能是系統初始化的行程嗎?以我的ubuntu為例,
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.2 2528 1268 ? Ss 14:49 0:01 /sbin/init
最小到1,沒有0,那這個德國高人,寫0,顯然是另有所指,google 一下
pid 0,有人說用ps -ef,在我的ubuntu上。也沒有0.
一般fork()出來行程,以筆者的ubuntu為例,也是
27xx,或28xx,一般常識判斷,得到0的機會不大,得到-1,還比較大。
玄機往往就在這裏,心理同時也有一些CALL BACK FUNCTION, 或是hook 想法,
這些讓程式的跑法,不如預期的程式寫法。
先從另一個線索,
以mattows SHOW在console的訊息,
mattows [2771]: Waiting for connections on port 8000
mattows [2886]: Accepted connection from 127.0.0.1:51639
mattows [2886]: Executing hellow.cgi
mattows [2771]: Child process 2886 exited with status 0
一個requset的處理,它會秀出4段log。
用Child process 去 grep source ,發現
/* clean up dead children */
static void child_reaper(int sig)
{
int status, pid;
while(0 < (pid = waitpid(-1,&status,WNOHANG)))
mywarn("Child process %d exited with status %d\n",pid,status);
}
這個function下中斷點,可以停下來,
這個child_reaper
給了筆者下一個線索。
struct sigaction sa = {
.sa_handler = &child_reaper,
.sa_flags = SA_NOCLDSTOP
};
sigaction(SIGCHLD,&sa,NULL);
sigaction是一個
The sigaction() system call is used to change the action taken by a process on receipt of a specific signal.
來源自http://linux.die.net/man/2/sigaction
這個系統呼叫,可以用來改變一個傳回的指定信號的動作。
以本例來說,
接收到SIGCHLD(子行程建立後),去執行child_reaper,檢查子行程是否還殘留。
學到一個系統呼叫的用法,雖然仍沒有找出無法trace的原因。
寫到這裏,筆者突然發現,似乎誤解了fork()回傳值的意思,
再google一下fork(), 中文資料很多。
返回值:
-1 : 失敗。
0 : 子程序。0 : 將子程序的process id傳回給父程序。
所以 case 0,是對的。之前以為只傳回process id或失敗,原來真的有傳回0
。
那為什麼不進來 case 0??
看來筆者要使出終極絕招---->寫信給原作者,雖然不會德文(網址是de),看他
網站內容,程式註解都用英文,用英文寫,應該可以吧,不知道他有沒有提供
technology support?
結論:
隨著對system call的理解,可以了解,不同人使用方式不一樣,如cheetah的作者就沒用sigaction。
網際網路google的大量訊息泛濫,帶來了程式人員的好處,
尤其是應用程式的code,大多可以google到sample code。
通常google 來的code,不太關底層架構,湊和著,通常都可以用,
但是code拿到了,trace不出想要的方向,這時,google到原作者的網站,
發個mail,有時也是不錯的方法 。
等待的同時,仍然可以繼續進行專案的其他部分,IT從業人員,常常是有超的求知慾,不解出來就不眠不休,這時候,如果專案蠻大的話,就要暫時放下,
先完成專案的其他部分,大家都有類似的經驗,有時搞了4/5個小時沒解的bug,
出去跑兩圈,洗個澡,回頭看一下,改一下,就解了。這時反而會回頭咒罵幹嘛多花那4/5個小時。
PS:在看其他邦友分享的文章時,意外發現,C語言之父走了,
一直以為瑞奇先生,和SQL發明者,是不少IT從業人員的衣食父母,
因為很多人很靠此維生,甚至有不錯的收入,哈佛某教授好像有講過,
利害的人是創業自己當老闆,差一點的是被人找去當管理者,更高明的是
自己無中生有一個產業,瑞奇先生發明C語言又共同發明UNIX, 是兩倍的高明。