用go想做一個http代理的小工具:
func main() {
listener, err := net.Listen("tcp", ":8080")
if err != nil {
log.Panic(err)
}
for {
client, err := listener.Accept()
if err != nil {
log.Panic(err)
}
go handleClientRequest(client)
}
}
func handleClientRequest(client net.Conn) {
if client == nil {
return
}
defer client.Close()
var buf [1024]byte
n, err := client.Read(buf[:])
if err != nil {
log.Println(err)
return
}
fmt.Println("recv msg:", string(buf[0:n]))
}
1024個字節(jié)不一定夠,肯定要有個結束標志吧?
Http協(xié)議是建立在TCP協(xié)議基礎之上的,當瀏覽器需要從服務器獲取網頁數(shù)據(jù)的時候,會發(fā)出一次Http請求。Http會通過TCP建立起一個到服務器的連接通道,當本次請求需要的數(shù)據(jù)完畢后,Http會立即將TCP連接斷開
TCP協(xié)議通過發(fā)送FIN包來釋放連接,所以FIN包就是結束標志,也就是說一直接收直到連接斷開就接收完了。
但是
隨著時間的推移,html頁面變得復雜了,里面可能嵌入了很多圖片,這時候每次訪問圖片都需要建立一次tcp連接就顯得低效了。因此Keep-Alive被提出用來解決效率低的問題。從HTTP/1.1起,默認都開啟了Keep-Alive,保持連接特性,簡單地說,當一個網頁打開完成后,客戶端和服務器之間用于傳輸HTTP數(shù)據(jù)的TCP連接不會關閉,如果客戶端再次訪問這個服務器上的網頁,會繼續(xù)使用這一條已經建立的連接Keep-Alive不會永久保持連接,它有一個保持時間,可以在不同的服務器軟件(如Apache)中設定這個時間。雖然這里使用TCP連接保持了一段時間,但是這個時間是有限范圍的,到了時間點依然是會關閉的,所以我們還把其看做是每次連接完成后就會關閉。
那么開啟了Keep-Alive之后該如何判斷結束呢?
其實,HTTP頭有個content-length,這個就是HTTP包正文長度了
當然也有沒有content-length的情況,那就是使用了分塊編碼(chunked encoding)數(shù)據(jù)是分為一系列的塊來發(fā)送的,每塊都有大小說明。哪怕服務器在生成首部的時候不知道整個實體的大?。ㄍǔJ且驗閷嶓w是動態(tài)生成的),仍然可以使用分塊編碼傳輸若干已知大小的塊。
編碼使用若干個Chunk組成,由一個標明長度為0的chunk結束,每個Chunk有兩部分組成,第一部分是該Chunk的長度和長度單位(一般不寫),第二部分就是指定長度的內容,每個部分用CRLF(全稱carriage
return/line feed 回車換行)隔開。在最后一個長度為0的Chunk中的內容是稱為footer的內容,是一些附加的Header信息(通??梢灾苯雍雎裕?/p>
另外HTTP消息頭與消息正文之間通過CRLF(回車換行),rnrn
來分隔