一般認為Web服務器程序是一個長時間(後台)運行的程序(即,守護程序,daemon) -> 此類程序會被以進程的形式初始化,守護進程程序的名稱通常以字母“d”結尾,如httpd。通常由客戶發起請求可以簡化協議和程序本身,某些復雜的網絡應用需要異步回調(asynchronous callback)通信,由服務器向客戶發起請求信息。
在一個多任務的電腦操作系統中,守護進程(英語:daemon,英語發音:/ˈdiːmən/或英語發音:/ˈdeɪmən/)是一種在後台執行的電腦程序。此類程序會被以進程的形式初始化。守護進程程序的名稱通常以字母“d”結尾:例如,syslogd就是指管理系統日志的守護進程。
通常,守護進程沒有任何存在的父進程(即PPID=1),且在UNIX系統進程層級中直接位於init之下。守護進程程序通常通過如下方法使自己成為守護進程:對一個子進程運行 fork,然後使其父進程立即終止,使得這個子進程能在 init 下運行。這種方法通常被稱為“脫殼”。
系統通常在啟動時一同起動守護進程。守護進程為對網絡請求,硬件活動等進行響應,或其他通過某些任務對其他應用程序的請求進行回應提供支持。守護進程也能夠對硬件進行配置(如在某些Linux系統上的devfsd),運行計劃任務(例如cron),以及運行其他任務。
在DOS環境中,此類應用程序被稱為駐留程序(TSR)。在Windows系統中,由稱為Windows服務的應用程序來履行守護進程的職責。
在原本的Mac OS系統中,此類應用程序被稱為“extensions”。而作為Unix-like的 Mac OS X有守護進程。(在Mac OS X中也有“服務”,但他們與Windows中類似的程序在概念上完全不相同。)
書上第5頁的程序,時間獲取客戶程序:
#include "unp.h" int main(int argc, char **argv) { int sockfd, n; char recvline[MAXLINE + 1]; struct sockaddr_in servaddr; if (argc != 2) err_quit("usage: a.out <IPaddress>"); if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) err_sys("socket error"); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(13); /* daytime server */ if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) err_quit("inet_pton error for %s", argv[1]); if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) err_sys("connect error"); while ( (n = read(sockfd, recvline, MAXLINE)) > 0) { recvline[n] = 0; /* null terminate */ if (fputs(recvline, stdout) == EOF) err_sys("fputs error"); } if (n < 0) err_sys("read error"); exit(0); }
使用的前提是需要有unp.h,配置方法摸我
主要步驟:
定義包裹函數(wrapper function) -> 約定首字母大寫,有助於代碼的簡潔,可以實現錯誤處理。
以下用包裹函數來寫一個時間獲取的服務器程序:
#include "unp.h" #include <time.h> int main(int argc, char **argv) { int listenfd, connfd; struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(13); /* daytime server */ Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); for ( ; ; ) { connfd = Accept(listenfd, (SA *) NULL, NULL); ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); Write(connfd, buff, strlen(buff)); Close(connfd); } }
主要步驟:
測試通過的代碼(unpv13e中的代碼配置方法見之前的文章,部分.h文件直接從lib文件夾中的.c文件改名而來): 碼雲