main函數分析;
一,參數設置: 讀取命令行參數
配置文件參數
讀取參數,設置對應的全局變量。主要參數有:配置文件;資源目錄;進程ID文件;日志文件;字符集;主機名及端口號...
二,參數處理:重點分析,主機名及端口號,damon
1,主機名及端口號
解析主機名,獲取對應IP地址,初始化監聽套接字(包括:socket,bind,listen)
以IPv4為例:
listen_fd=socket(AF_INET,SOCK_STREAM,0);創建套接字
套接字選項設置:設置方法有fcntl,setsockopt
1,fcntl(listen_fd,F_SETFD,FD_CLOEXEC); 設置close-on-exec,exec進程時,關閉此文件描述符
2, int i=1;
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,(void*)&i,sizeof(i));可重用本地地址
3,bind(listen_fd,struct sockaddr* -,sizeof(-));綁定套接字和IP:端口
4,listen(listen_fd,1024);設置監聽套接字最大隊列長度
2,若不是調試模式,則應該設置為damon模式,
switch(fork()){
case 0: break; 子進程繼續執行
case -1: 出錯,退出程序
default:exit(-1); 父進程退出
}
3,信號處理設置:
SIGTERM: kill發送系統中斷進程信號
SIGINT: 用戶終端Ctrl+C中斷進程
SIGHUP:一般用來通知守護進程再次讀取配置文件等作用,因為守護進程沒有終端,不會收到此信號。此處用於再次讀取日志文件
SIGCHLD:子進程退出時,會發送該信號給父進程,父進程應該捕捉,否則將產生僵屍進程
SIGPIPE:管道讀關閉時寫,套接字不再連接時寫,都會產生此信號。網絡編程中出現的很多
4,服務器主循環:
若收到SIGHUP信號,則再次打開日志文件(覆蓋),若需要可備份
select模式,多路復用:阻塞模式
FD_ZERO(&lfdset);清空描述符集
FD_SET(listen_fd,&lfdset);條件套接字描述符到描述符集中
設置select阻塞讀,select(listen_fd+1,&lfdset,NULL,NULL,NULL);永遠阻塞,直到listen_fd可讀;
若listen_fd可讀,調用accept,獲得已連接套接字描述符,若出錯(EAGAIN,資源暫不可用;EINTR,中斷函數調用;ECONNABORT,連接中斷。continue,try again),否則異常退出。
若連接成功,fork(),子進程處理請求,父進程繼續循環,監聽。
子進程關閉監聽套接字,調用 handle_request 函數處理請求,退出;父進程關閉已連接套接字,繼續循環監聽。
5,handle_request函數解析
超時設置:利用信號SIGALRM,alarm(60);
[設置TCP_NOPUSH套接字選項]
讀取請求:循環read,把讀取的數據存入全局變量request中,每次讀取后,重新設置超時alarm(60)
請求解析: get_request_line()
解析請求的第一行:分三部分:方法,路徑,協議
解析請求其余部分:name:value...初始化對應的全局變量
方法字符串分解:方法(GET,HEAD,POST),查詢字符串query,?之后
路徑解析:獲取文件名file
超時設置,SIGALRM(寫超時設置)
響應:構造請求響應(報頭及實體),寫套接字(循環write),發送響應。