最開始我們需要明白一件事情,因?yàn)檫@是這篇文章的前提:
HTTP協(xié)議只是一個(gè)應(yīng)用層協(xié)議,它底層是通過TCP進(jìn)行傳輸數(shù)據(jù)的。因此,瀏覽器訪問Web服務(wù)器的過程必須先有“連接建立”的發(fā)生。
而有人或許會問:眾所周知,HTTP協(xié)議有兩大特性,一個(gè)是“無連接”性,一個(gè)是“無狀態(tài)”性。這里的“無連接”豈不是跟上面的說法有沖突?其實(shí)這里并沒有矛盾,只是人們對“連接”這個(gè)詞的理解有差異。首先我們來看一下瀏覽器向Web服務(wù)器發(fā)出Http請求以及Web服務(wù)器給瀏覽器回復(fù)的過程:
用圖表示以上過程:

圖1
如上圖1所示。瀏覽器向Web服務(wù)器發(fā)送http請求之前,需要先建立連接。沒錯(cuò),它們間建立連接的過程跟我們平時(shí)開發(fā)socket程序類似。由此可知,HTTP協(xié)議的“無連接”特性并不是指:瀏覽器與Web服務(wù)器進(jìn)行數(shù)據(jù)交換時(shí),不需要建立連接。那么“無連接”特性到底指什么呢?我們再看圖1會發(fā)現(xiàn),瀏覽器每次請求完畢后都會與服務(wù)器處于“斷開”狀態(tài),下一次請求時(shí)再重新與服務(wù)器建立連接。HTTP的無連接特性恰恰就是指瀏覽器的每次請求都必須重新與服務(wù)器建立連接,正常情況下,瀏覽器不會與Web服務(wù)器保持長時(shí)間的連接狀態(tài)。現(xiàn)將HTTP協(xié)議的兩大特性歸結(jié)如下:
服務(wù)器與瀏覽器之間的一次連接只處理一個(gè)http請求,請求處理結(jié)束后,連接斷開。下一次請求再重新建立連接。
服務(wù)器不會保存瀏覽器信息。也就是說,在服務(wù)器端,第一次http請求處理的結(jié)果不會保留到第二次請求。如果第二次請求處理時(shí),需要用到第一次請求處理的結(jié)果,瀏覽器在第二次請求時(shí),必須將第一次處理結(jié)果重新傳回給Web服務(wù)器(比如使用cookie)。
關(guān)于“協(xié)議”:
這個(gè)話題有點(diǎn)大,不是我能掌控得了的。不過對于今天這篇文章,我還是盡最大可能說一點(diǎn)。計(jì)算機(jī)中協(xié)議范疇廣泛,單就網(wǎng)絡(luò)通信中的協(xié)議,就不計(jì)其數(shù),OSI七層中每層都很多種協(xié)議。那么協(xié)議到底本質(zhì)上是個(gè)什么東西呢?單就通信中的協(xié)議來講,協(xié)議的本質(zhì)其實(shí)就是一種數(shù)據(jù)結(jié)構(gòu),類似代碼中的結(jié)構(gòu)體,說得再底層一點(diǎn),就是一個(gè)字節(jié)流,規(guī)定好了第一個(gè)字節(jié)代表什么、第二個(gè)字節(jié)代表什么等等。
協(xié)議的作用跟我們平時(shí)所說的“契約”、“約定”類似,一個(gè)團(tuán)隊(duì)合作的任務(wù),合作各方必須同時(shí)遵守事先的約定,最后工作才能正常進(jìn)行下去。網(wǎng)絡(luò)通信中也一樣,通信雙方收/發(fā)數(shù)據(jù)時(shí)必須按照實(shí)現(xiàn)規(guī)定好了的結(jié)構(gòu)去發(fā)送/接收,一方不遵守該規(guī)范,通信就不能成功。這里說的結(jié)構(gòu)規(guī)范其實(shí)就是“協(xié)議”。協(xié)議有以下作用:
就網(wǎng)絡(luò)通信協(xié)議來講,應(yīng)用層協(xié)議與我們程序開發(fā)最為密切(至少對我們使用c#、java的人來講),其他向tcp、udp等傳輸層協(xié)議幾乎用不到。我們開發(fā)的通信程序,必須遵守實(shí)現(xiàn)定義好了的應(yīng)用層協(xié)議,比如瀏覽器和Web服務(wù)器都遵守了HTTP應(yīng)用層協(xié)議,只有這樣,它們才能正常交互。倘若我們自己開發(fā)一個(gè)程序,正確地遵守了HTTP協(xié)議,那么我們的程序也能夠像Chrome、IE等瀏覽器一樣,去訪問Web服務(wù)器。
文章末尾有一個(gè)使用socket模擬瀏覽器請求Web服務(wù)器的demo,實(shí)現(xiàn)的功能我們完全可以使用類似WebClient、WebRequest等類型去實(shí)現(xiàn)。demo功能如下:
(開發(fā)這樣的程序需要我們充分熟悉socket編程、HTTP協(xié)議格式)
以下是發(fā)送HTTP請求的代碼:

1 /// <summary> 2 /// 發(fā)送請求 3 /// </summary> 4 /// <param name="socket"></param> 5 PRivate void SendRequest(Socket socket) 6 { 7 string h1 = "GET " + _path + " HTTP/1.1/r/n"; 8 string h2 = "Accept: */*/r/n"; 9 string h3 = "Accept-Language: zh-cn/r/n";10 string h4 = "Host: " + _host + "/r/n";11 string h5 = "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36/r/n";12 string h7 = "Connection: close/r/n/r/n";13 14 byte[] send_buffer = Encoding.UTF8.GetBytes(h1 + h2 + h3 + h4 + h5 + h7);15 socket.Send(send_buffer);16 Print("請求發(fā)送完畢,等待Web Server回復(fù)...");17 socket.BeginReceive(_buffer, 0, 640 * 1024, SocketFlags.None, new AsyncCallback(OnReceive), socket);18 }View Code
下面是效果圖:

圖2
源碼下載:http://files.VEVb.com/xiaozhi_5638/socket_browser.rar
新聞熱點(diǎn)
疑難解答
圖片精選