一般認為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文件改名而來): 碼雲
