tinyhttpd 是一個不到 500 行的超輕量型 Http Server,用來學習非常不錯,可以幫助我們真正理解服務器程序的本質。
main
|<--------------------^
V |
start ----> start_up_port ---> accept ---> create_thread ---> accept_request ---> end
start_up_port:開啓指定(或隨機)的端口,並將端口與httpd服務綁定。指定端口開始監聽http請求。
accept:指定端口監聽到http請求
create_thread:創建一個線程執行accept_request來處理請求
start_up_port —>accept
一套標準的socket->bind->listen->connect->accept流程
socket:生成一個socket文件描符
bind:綁定了服務器要監聽的ip/port
listen:對這對ip/port進行監聽
connect:客戶端請求連接
accept:服務器調用accept()接受客戶端連接請求,並分配新的ip/port與客戶端通信,之前的ip/port繼續監聽
accept_request
start
|
get_line:讀取請求的字符串
|
獲取method:字符串中的第一個參數
/ | \
POST方法 GET方法 其它方法
| | |
cgi = 1 | end
\ /
獲取url:字符串第二個參數
|
method==GET && url中包含'?'
/ \
否 是
| |
| url從?截斷
| query_string指令url?以後的部分
| cgi = 1
\ /
格式化 url 到 path:path表示瀏覽器請求的服務文件路徑,若path爲文件夾,默認在path後加上index.html
|
判斷cgi的值
/ \
爲0(無參的GET) 爲1(POST或有參的GET)
| |
serve_file: execute_cgi
輸出服務器文件到瀏覽器 執行 cgi 腳本
| |
end end
serve_file
用於處理無參的GET方法的請求。
處理方法是把文件的內容輸出到瀏覽器。
文件的地址就是解析出來的url
start
|
把剩下的數據扔掉
|
headers:構造消息頭,並send
|
cat:讀取文件內容,並send
|
end
execute_cgi
用於處理POST方法或帶參數的GET方法。
由於需要執行CGI腳本,因此會新建一個進程。
start
/ \
GET方法 POST方法
| |
把剩下的數據扔掉 剩下的數據, 提取Content-Length,其餘扔掉
\ /
建立管道cgi_output
|
建立管道cgi_input
|
新建一個進程
|
把 HTTP 200 狀態碼寫到套接字
/ \
父進程 子進程
| |
配置管理 配置管理
| |
| 配置cgi運行環境
| |
把數據寫到input--->從STDIN讀數據
| |
| 執行CGI文件(文件路徑爲path)
| |
從cgi_output讀取<---執行結果輸出到STDOUT
| |
send end
|
end