本篇文章主要介紹go語言基于tcp協(xié)議實(shí)現(xiàn)簡(jiǎn)單的http服務(wù)器,大家可以學(xué)習(xí)到:
1.怎樣實(shí)現(xiàn)一個(gè)簡(jiǎn)單的http服務(wù)器
2.通過錯(cuò)誤的http協(xié)議格式加深對(duì)http協(xié)議的理解
平時(shí)我們使用的http服務(wù)器,如:apache、nginx都是一個(gè)完整而且功能強(qiáng)大的服務(wù)器,如果我們不去看源碼無法很好地理解http服務(wù)器的內(nèi)部實(shí)現(xiàn)。如果我們不去自己實(shí)現(xiàn)一個(gè)簡(jiǎn)單的http服務(wù)器,可能就無法很好地理解http協(xié)議,我們學(xué)習(xí)應(yīng)該不僅要知其然還要知其所以然。
本篇文章從tcp協(xié)議開始介紹,之后使用tcp socket按照http協(xié)議格式發(fā)送數(shù)據(jù)到客戶端,這里的客戶端指的就是瀏覽器。
傳輸控制協(xié)議(TCP,Transmission Control Protocol)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。
tcp協(xié)議屬于傳輸層協(xié)議,http協(xié)議屬于應(yīng)用層協(xié)議,http協(xié)議位于tcp協(xié)議之上,也是http協(xié)議是基于tcp協(xié)議實(shí)現(xiàn)的。很多應(yīng)用層協(xié)議都是基于tcp協(xié)議實(shí)現(xiàn)的,如:文件傳輸協(xié)議ftp、ssh協(xié)議、telenet協(xié)議等。
下面開始我們的編程之旅!
首先監(jiān)聽本地tcp 8888端口
listen, err := net.Listen("tcp", "127.0.0.1:8888")
之后打印監(jiān)聽信息
fmt.Println("server start listening on port 8888")
接著延時(shí)關(guān)閉tcp流
defer listen.Close()
之后for循環(huán)進(jìn)入監(jiān)聽,如果有連接進(jìn)來啟動(dòng)goroutine進(jìn)行處理
go
接著我們來看下handleClient函數(shù)的實(shí)現(xiàn)
go
handleClient函數(shù)里面首先定義了響應(yīng)體,打印響應(yīng)體的長度。之后定義響應(yīng)頭,響應(yīng)頭以“HTTP/1.1 200 OK\n”開始,這是http協(xié)議的標(biāo)準(zhǔn)響應(yīng)頭,之后定義響應(yīng)類型和響應(yīng)體的長度。響應(yīng)頭和響應(yīng)體之間以“\n\r\n”分割。
最后以字節(jié)格式發(fā)送給瀏覽器。
下面我們來看下執(zhí)行效果吧!在瀏覽器中輸入
http://127.0.0.1:8888/
瀏覽器
可以看到瀏覽器中顯示出我們啟動(dòng)的服務(wù)器返回的數(shù)據(jù)。Response Headers中的響應(yīng)頭正是我們?cè)O(shè)置的。
恭喜你,完成了自己的http服務(wù)器!
但是凡事我們要舉一反三,我們?cè)賮碓囈幌氯绻鹔ttp狀態(tài)是500時(shí),返回的結(jié)果是什么?
http
瀏覽器
這個(gè)http 500就是我們?cè)陂_發(fā)中經(jīng)常遇到的,現(xiàn)在我們自己模擬實(shí)現(xiàn)了。
我們可以嘗試去掉響應(yīng)頭和響應(yīng)體之間的分隔符
http
我們看下結(jié)果
瀏覽器
結(jié)果是瀏覽器無法識(shí)別,這就是為什么會(huì)有http協(xié)議,先規(guī)定協(xié)議各家瀏覽器按照協(xié)議實(shí)現(xiàn),這樣就不會(huì)出現(xiàn)問題。