分分钟手写http server
許久之前,在我還不會寫socket的時候(其實(shí)現(xiàn)在也還不會),看到了ChinaUnix上一個寫文件瀏覽器的帖子,400來行的樣子,下過來跑了一下,能在瀏覽器里訪問目錄,下載文件,真是神奇極了。后來,我開始看UNP了,學(xué)了點(diǎn)兒socket編程的時候,立馬就心動要自己動手寫一個了。文件瀏覽么,和socket相關(guān)的其實(shí)也沒有多少,更多的是系統(tǒng)調(diào)用(例如stat獲取文件信息)和HTTP協(xié)議。寫完之后,略有些失落。然后,看到了mini_httpd,短短3K行出頭的代碼,把HTTP服務(wù)器的基本特性都實(shí)現(xiàn)了,而且速度還不慢。詳情看鏈接。
然后,粗略看了一眼代碼邏輯之后,我也開始了。
期間,翻了一遍《http權(quán)威指南》,終于知道之前爬豆瓣讀書被封的原因(沒注意robots.txt文件中對爬蟲速率有限制)。
寫一個簡單的http服務(wù)器,首先要理清業(yè)務(wù)邏輯。在請求到來之前,服務(wù)器需要設(shè)置好相關(guān)的環(huán)境變量,例如端口號,根目錄,日志文件等。然后就是等待請求的到來了。
為了增加篇幅,先列一下HTTP請求格式:
通用格式為:
請求方式 ? ?請求路徑(如果是get且?guī)?shù)則參數(shù)會跟在路徑后面,以一個?分隔) ? ?協(xié)議版本號(例如HTTP/1.1)
其他請求頭(以名稱:值)的形式分行出現(xiàn),一行一個。
請求首部以一個空行結(jié)束。在程序中反應(yīng)出來就是\r\n兩遍結(jié)束首部內(nèi)容。
請求之后是請求包的數(shù)據(jù)部分,對如今的瀏覽器來說,似乎都需要有一個content-length首部標(biāo)記,不然會卡在那里等待。
收到請求之后,服務(wù)器,首先分析請求頭(即第一行),獲取請求方式,如果方式未實(shí)現(xiàn)則返回400錯誤。然后是分析請求url,通常這里是相對URL,在首部里還有一個host標(biāo)記,但有一段時間我收到了好多次絕對URL,導(dǎo)致URL處理錯誤,百思不得其解,郁悶。
對于POST請求來說,關(guān)鍵在于,如果帶參數(shù),則參數(shù)跟在首部后面的請求數(shù)據(jù)中(GET請求通常沒有數(shù)據(jù)部分)。
根據(jù)這些信息,基本就可以開始寫了。期間令我糾結(jié)的還有一個問題,對于一般的HTTP服務(wù)器來說,不可能僅僅用于顯示單純的靜態(tài)頁面,還需要根據(jù)參數(shù)顯示不同的頁面,而靜態(tài)的HTML頁面并不能夠處理參數(shù)。所以,練手的話可以選擇使用cgi方式,即把參數(shù)傳遞到cgi程序去,然后讓cgi程序生成頁面顯示。具體的實(shí)現(xiàn)使用exec函數(shù),需要注意的更多的是html中form的跳轉(zhuǎn)似乎要加相對路徑及文件全名,也就是說,form里action寫了什么就會跳轉(zhuǎn)到什么地方去。單純寫個文件名就會跳轉(zhuǎn)到文件名那個文件去(實(shí)際上可能帶后綴名)。
處理請求時,通常建議fork一個新進(jìn)程去處理,方便快捷。關(guān)于響應(yīng)中首部的填寫,需要注意的是content-length,content-type,Connection幾項(xiàng),其他的,隨意了。
然后,實(shí)現(xiàn)過程中主要用到的一些函數(shù)。按照業(yè)務(wù)邏輯來:
程序啟動后,處理參數(shù),除了自己寫外,還可以用系統(tǒng)提供的getopt和getopt_long,后者比前者多了類似--host的支持,不過稍微測試了下,發(fā)現(xiàn)似乎有bug,例如-a合法,--b不合法,但--ba合法(大致是這樣)。需要注意的是,短參數(shù)是根據(jù)參數(shù)選項(xiàng)后面有沒有冒號來判斷是否有參數(shù)值的(-h localhost這種),也就是說如果每個選項(xiàng)都要有參數(shù)值,則參數(shù)字符串應(yīng)該以一個冒號結(jié)尾,例如我的:"H:P:R:"。
socket相關(guān)函數(shù),我用簡單、粗暴的read和write以及close等
收到請求后,可以通過strcasecmp來比較,忽略大小寫,其余和strcmp一樣。然后就是根據(jù)access判斷請求的文件是否存在。如果文件存在,用stat函數(shù)判斷是否具有訪問權(quán)限以及獲取文件大小(在響應(yīng)中用于content-length首部)。
大致邏輯就是這樣了。熟悉了一下HTTP協(xié)議,又練了下socket編程。
轉(zhuǎn)載于:https://www.cnblogs.com/fityme/archive/2013/04/25/3043540.html
總結(jié)
以上是生活随笔為你收集整理的分分钟手写http server的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自定义实现ProgressDialog样
- 下一篇: 只列出目录