1. 程式人生 > >網路應用(8):http的封裝與使用

網路應用(8):http的封裝與使用

之前講過http的協議,怎麼約定請求或響應的行、頭、體,也介紹怎麼使用curl來完成http的請求。這一次,再接再厲,換一個角度換一些角色,再次說http的封裝與使用。反正目的只有一個:加深對http協議的理解。

(1)tcp的實現

說http的實現,非講tcp不可(為什麼?後面會解釋),而之前講tcp協議的使用,用到了socket,用socket就能通訊,就能做tcp想做的事情。

那socket是什麼東西?

用你的話來理解,socket是一個通道嗎?因為它能通訊啊。“socket是一個通道”已經是抓到重點了,雖然不完整,因為socket在成為通道前,並不是通道,它只是一個等待使用的值。但是,“突出重點”的抽象是如此重要,不要追求完整或完美。socket,是網路結點(ip:port),可以代表資料通道,通過它就可以在結點間傳送資料。 可以想象,網路上的一切資料交換,都由socket完成。

socket並不只是一個抽象的概念,它還是實實在在的程式碼實現,但你能看到的是二進位制程式碼,它已經給別人實現了,而且存在於各個平臺,比如windows、unix、ios、android等,那它在這些平臺是什麼樣的存在?它又是誰實現的呢?

結合wiki等網頁的資訊:

套接字起源於20世紀70年代加州大學伯克利分校版本的Unix,所以,這個套接字稱為“伯克利套接字”或“BSD套接字”。 BSD sockets,是所有其它平臺的socket的祖先,包括windows/liunx,還有某些語言使用的socket比如python、java等。bsd socket用c語言實現,有對應的c層靜態庫(或動態庫)。

windows的socket是Martin Hall、Mark Towfiq(從屬於Microsoft)等人的版權,有兩個大版本,即winsock1跟winsock2,對應的庫檔案是wsock32.lib/ws2_32.lib,你在windows平臺上就是在使用這個庫檔案進行socket操作。

好了,具體某些平臺是誰寫了socket的實現,就不深究了,只是說,感謝前輩們的貢獻。

那問題來了,socket實現了什麼?

socket實現了tcp協議(還有udp),這個很重要,對於http來說也很重要,因為http在協議棧上位於應用層,依賴於傳輸層的tcp協議,也就是說,http最終要用tcp來傳輸資料,而socket包括了tcp的實現,你說重不重要?

所以,http協議依靠socket來傳輸資料,但依靠還依靠,不代表http要理socket層的事情。

(1)http的實現

http跟tcp不同,http並不關心資料怎麼傳來傳去,反正能傳就行,這個是tcp層的事情,那http還要考慮什麼?就是請求與響應的格式啊,而且是人能讀懂的格式,http的要求已經很人性化了,這個對話已經很友好了(不像tcp的資料)。http報文的格式之前介紹了的!

對於http請求或響應資料,包括行、頭、體,其中行與頭是少不了的。那行頭體的格式由誰來封裝,注意,這不是socket的事情,socket不管這個,那誰管?

工具curl管http格式封裝(也管資料收發),java的HttpClient管http格式封裝,python的urllib也管http格式封裝,還有很多工具類或庫都能封裝http協議(注意,說http就只有http協議,不包括tcp,因為tcp是另一層的事情),當然,你自己寫一個http的格式封裝,也沒有問題。

簡單來說,http的實現其實並不包括怎麼傳輸的事情,那是tcp層(socket)的事情,http的實現重點在於本身協議的封裝與實現,比如怎麼組裝請求頭、怎麼呼叫介面收發資料、怎麼解釋資料、GET或POST方式封裝、url編碼,等等。你會發現有很多零散的知識點,很多實現還跟業務關係密切,這也是http是應用層協議的表現。

對於你,如無必要,優先考慮已經穩定的http封裝實現吧,具體看你是什麼平臺進行對應的選擇。

(2)http的使用

之前講http的結構跟怎麼使用curl時,其實就是通過curl使用了http。是的,我們並不會直接“使用http”,而是通過工具類來使用http,你可以自己寫工具類比如弄一個httpclient的類出來,也可以使用一些表現良好的現有的工具類,建議用後者。

這一次,我用python庫的一些工具,比如urllib或httplib,通過它們來使用http協議。

一般使用http,就是要向伺服器發出請求,那伺服器怎麼來?你自然可以找一堆伺服器出來,只要有對應的url就可以,實際上你也只是請求某個url。但是,為了顯得高階一點,我這裡自行定製一個web伺服器,用來接收http請求。

如何定製web伺服器?

小程在介紹“PHP程式”的使用時,把apache給引了進來,apache是一個web伺服器,可以接受你的http請求。另一方面,apache可以跟PHP解析器、python解析器等進行互動,可以根據http請求,執行一些指令碼程式碼(像php指令碼或python指令碼等)。

這裡就演示一下,怎麼發起一個http請求到apache,apache再執行python指令碼,返回http響應。

(a)讓apache能啟用python

按之前講解的知識,apache專案的目錄是:/Library/WebServer/Documents,之前php指令碼就是放在這裡。但是,對於python指令碼,解釋它的是cgi,這些指令碼要放在cgi專案目錄,那個目錄是:/Library/WebServer/CGI-Executables,所以你寫的python指令碼要放在這個目錄。 先不管那麼多,在CGI-Executables目錄下,建立一個hello.py,隨便寫點什麼,比如:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

title="小程"
info="你好,first py script,關注微信公眾號'廣州小程'"
htmlcontent="<html><head><meta charset='utf-8'><title>%s</title></head><body><h2>%s</h2></body></html>" % (title,info)
print("Content-type:text/html")
print("")
print(htmlcontent)

然後開啟瀏覽器來請求一下這個檔案吧(注意請求cgi-bin目錄),結果是這樣的:

顯然,這不是我想看到呀,我不是要看指令碼程式碼,我是想看到指令碼程式碼被解釋後的內容!

如果客戶端比如瀏覽器,向apache請求了python或php指令碼,而apache沒有找到對應的指令碼直譯器的話(注意apache自己是不懂指令碼解釋的),apache會把這個指令碼的內容完整地返回給瀏覽器,這時原始碼暴露無遺,這很可能不是你想看到的事情。

所以,讓apache找到指令碼直譯器(這裡是cgi),是至關重要的一步。

不再講apache的啟用了,直接講,怎麼樣才能讓apache執行python指令碼呢?你可能還記得,讓apache呼叫php程式的話,要把apache的配置檔案httpd.conf改一下(/private/etc/apache2目錄下),也就是“LoadModule phpx_module...”這一行解除註釋,就可以呼叫php程式了,那對於python是不是也這樣改呢?是的,bingo,也要解除註釋,這一句是:

#LoadModule cgi_module libexec/apache2/mod_cgi.so

把前面的#去掉並儲存一下即可,注意重啟一下apache:

sudo apachectl restart

這時,apache就會載入mod_cgi.so,並用cgi來解釋python指令碼。再用瀏覽器請求一次,看到這樣的返回:

簡單來說,cgi就是用來解釋python指令碼的,apache啟用它就解決了python指令碼解釋的問題,更多cgi的東西不說了。

(b)伺服器處理http請求

至此,apache已經可以執行我寫的python指令碼了,那我寫這個hello.py來做什麼呢?當然是處理瀏覽器發過來的http請求了。所以,把hello.py再修改一下,讓它根據請求的引數值,返回不同的內容給瀏覽器,比如這樣:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import cgi

title="廣州小程"
info=""
paras = cgi.FieldStorage()
if paras.has_key('secret'):
    if paras['secret'].value=='free':
        info="<h1>welcome, you are so clever! secret is %s</h1>" % paras['secret'].value
    else:  
        info="<h1>wrong! secret is NOT '%s'</h>" % paras['secret'].value
else:
    info="<h1>NO! 請加上secret引數!</h1>"
htmlcontent="<html><head><meta charset='utf-8'><title>%s</title></head><body>%s</body></html>" % (title,info)
print("Content-type:text/html")
print("")

指令碼中使用cgi.FieldStorage獲取請求引數,對這個引數給出了不同的提示。用瀏覽器請求一下,傳遞不同的引數,可以看這樣的展示:


至此,一切都是美好的,伺服器指令碼定好了,能應對請求了,瀏覽器也看到返回內容了,可是,我不是教你怎麼做web服務啊,我想說的是,怎麼使用http協議的呀!

(c)在python中使用http協議

這個才是重點內容。這裡演示寫一個客戶端,用python裡面的類,完成http請求,以表示,我已經會使用http協議了!

分別用urllib2跟httplib來演示。

import urllib2
url='http://localhost/cgi-bin/hello.py?secret=free'
req=urllib2.Request(url)
res=urllib2.urlopen(req)
res=res.read()
print(res)

執行上面的程式碼,使用urllib2這個http協議封裝類,發起請求,返回是這樣的:

import httplib
url='http://localhost/cgi-bin/hello.py?xx'
conn=httplib.HTTPConnection('localhost')
conn.request(method='GET', url=url)
res=conn.getresponse()
res=res.read()
conn.close()
print(res)

這一段程式碼就形象很多了,先用HTTPConnection建立起連結(指定ip跟埠,埠省略意思就是用預設的80即web伺服器的預設埠,另外我的localhost是固定到本機的),然後發起request,再取響應,一氣呵成。執行結果是這樣的:

以上請求都是get方式,post也是很容易的,你研究一下嘛。好了,已經會用http協議了,至少是用上了。

總結一下吧,本文主要講怎麼使用http協議,為了說明白這個操作,講了tcp跟http的大道理,還講了怎麼讓apache解釋python指令碼,最後那一點演示才是重點,你至少知道有urllib這樣的類可以使用http協議了吧!


相關推薦

網路應用8http封裝使用

之前講過http的協議,怎麼約定請求或響應的行、頭、體,也介紹怎麼使用curl來完成http的請求。這一次,再接再厲,換一個角度換一些角色,再次說http的封裝與使用。反正目的只有一個:加深對http協議的理解。 (1)tcp的實現 說http的實現,非講tcp不可(為什麼?後面會解釋),而之前講tcp協議的

網路應用6http報文結構curl的使用

http是一個協議,協議就是約定、規定,先不管為什麼這麼約定有什麼高深的東西,為了解決具體問題,我們先要能使用協議,理解協議中對我們有用的那部分資料,是的,我們不是研究生,更不是純研究,所有的研究都要由具體的問題來驅動。 那這裡的具體問題是什麼?就是看懂http的請求跟回覆啊,就像寫某某申請一樣,你不理申請最

Postman高階應用8檔案變成了亂碼——下載檔案

背景 在做後臺管理系統時候,涉及到匯出報表等功能,如果我們用以前的方式請求,往往會看到返回一堆亂碼,而不是我們想要的檔案。其實Postman為我們提供了檔案下載功能,同樣普通的html文字和json資料也可以返回儲存為檔案。 實戰 點發送按鈕旁邊的三角形,然後點Send a

Shell應用8使用awk定位反彙編輸出

指令碼概述   由於使用objdump反彙編linux核心的輸出太多(2.6.32-220.el6.x86_64統計結果為1457706行),而很多時候只是想檢視特定部分的機器碼與彙編指令,例如函式的入口、堆疊、呼叫了哪個函式等,為了高效和通用,因此編寫了一個簡單的awk指令碼,其命令列引數說明如

手把手教你寫網路爬蟲8徹底解決亂碼問題

字元編解碼是爬蟲裡必學的一項知識,在我們的爬蟲生涯中早晚會爬到亂碼的網頁,與其遇到時驚慌失措,不如早學早好,徹底避免亂碼問題。 字元編碼簡介 什麼是字符集 在介紹字元編碼之前,我們先了解下什麼是字符集。 字元(Character)是各種文字和符號的總稱,包括各國家文字、標點

卷積神經網路簡單的應用模型構建訓練

模型構建文中採用了Tensorflow框架進行模型的構建,這裡簡單介紹下Tensorflow的安裝(在Anaconda上安裝):⑴Anaconda安裝:https://www.anaconda.com/download/,選擇支援py36的版本;⑵直接在命令列中安裝Tenso

網路應用1抓包獲取APP的重要資訊 | charles

小白:何為抓包? 小程:就是截獲網路上收發的資料包。 小白:網路上那麼多資料包,怎麼知道哪些是有用的? 小程:只截獲目標app的資料包就縮小了範圍,但即便是縮小了範圍,也需要進一步分析與排查。 小白:在垃圾堆裡找壞人的行動時間與地點嗎?這是使徒行者2的橋段啊,你有沒有看過? "抓

網路應用2流量位元速率等 | 流量、頻寬、速度、位元速率

架設網路,按規定,需要拿到工信部頒發的營業執照。我們使用的網路,由運營商提供。運營商指的是網路運營商(提供網際網路服務的組織,也叫ISP),包括:移動、電信、網通、鐵通、長城、天威、教育網、廣電、方正,等等。 現在,運營商提供網路,是收費的,收費的理由,主要還是運營商提供了通道(基站建議等),就相當收路費。那

網路應用3CDNP2P的概念

我前面說了流量的概念,流量是使用網路時經常要考慮的一個因素--如何才能更快的使用流量,如何才能節省流量使用的成本,對於這樣的問題,你可能要了解一下什麼是cdn,什麼是p2p。 (1)cdn是什麼 cdn是一個基於已有的internet網路而進行擴充套件的網路系統,叫作內容分發網路,content delive

網路應用4塊的概念 | Range

分塊來處理,也算是自然的想法,就是化整為零。而於對於檔案的下載同樣使用這個道理,既可整體下載,也可分塊下載。 小程這裡以http協議為例,來看一下塊的概念與使用。 http的range http1.0請求與返回檔案都是整體,不支援“只拿一部分資料”,伺服器也不支援斷點續傳(因為不支援從某個點開始拿部分資料),

VB6基本資料庫應用連線資料庫SQL語句的Select語句初步

資料庫我們已經建好了,重提一下上一章的結果,我們最後建立了一張Student的表,其中有StudentID(數字的雙精度型別)和StudentName(文字型別。補充一下,2013中有【長文字】和【短文字】,人名不會很長,根據上一章選擇儘量小的資料型別的規則,這裡就選【短文字】就可以了)。儘

深入學習Gremlin8資料分組去重

第8期 Gremlin Steps: group()、groupCount()、dedup()、by() 本系列文章的Gremlin示例均在HugeGraph圖資料庫上執行,環境搭建可參考準備Gremlin執行環境,本文示例均以其中的“TinkerPop關係圖”

Shell應用7nginx升級恢復

指令碼概述   nginx是一款著名的開源web伺服器,為方便升級與恢復,編寫了一個簡單的指令碼,因為升級備份了可執行檔案和配置檔案(字尾名為old),所以可用於恢復。當升級時,若nginx正在執行,則不中斷服務進行平滑升級,否則直接拷貝覆蓋;當恢復時,若nginx正在執行,則不中斷服務進行平滑恢

Python網路爬蟲chromdriver.exechrome版本對映及下載連結

前言:最近正在學習Python網路爬蟲,學到selenium,需要用到chrome瀏覽器的驅動,但是網上的很多地址都被牆了,而且沒有準確的驅動和chrome版本的對映,很麻煩。現在我已經解決了這些問題,現在把對映和下載連結分享出來。 (一)檢視chrome

Erlang8二進位制型位語法

大多數情況下,二進位制型裡的位數都會是8的整數倍,因此對應一個位元組串。 如果位數不是8的整數倍,就稱這段資料為位串。 二進位制型的編寫和列印形式是雙小於號和雙大於號之間的一列整數或字串2> &

卷積神經網路CNN8—— Pix2Pix Application -- Aerialmap Lane Line Detection (Pix2Pix應用航拍圖車道線檢測)

前言 GAN(Generative Adversarial Networks–https://arxiv.org/abs/1406.2661)自問世而來熱度一直無法退減,生成網路G與判別網路D通過相互對抗(原作者比喻成欺騙)訓練網路,最終得到可以生成以假亂真圖

計算機網絡相關應用層協議HTTP

toc connect html文本 con 也不會 http服務 lang 代碼 保存 前言 復習下計算機網絡的知識並記錄 正文 定義:HTTP協議(HyperText Transfer Protocol,超文本傳輸協議)是用於從WWW服務器傳輸超文本到本地瀏覽器的傳送協

卷積神經網路簡單的應用目的資料

目的構建一個卷積神經網路對性別以及美麗程度(beautiful or handsome)進行識別。資料準備模型中採用的資料來自百度搜索資料,為了效率可採用爬蟲(大家可以在以下相關程式碼上進行更改):http://blog.sina.com.cn/s/blog_13927ddb50102w2m1.html,下圖

卷積神經網路簡單的應用模型測試

模型測試模型訓練好之後通過重新載入模型的方式進行模型測試,使用Tensorflow中的Saver物件。相關程式碼如下:def test_cnn(x_data): output = create_cnn(4) saver = tf.train.Saver()

Unity如何實現網路通訊觀察者模式以及在網路模組的應用

    首先我們來說一下什麼叫觀察者模式。觀察者模式,顧名思義,就是觀察,那麼就會有觀察者和被觀察者,比如在軍隊中,所有的軍人要聽長官的指示,軍人就是觀察者,長官就是被觀察者,長官一聲號令:“向左轉!”,長官所有的監聽者就會執行向左轉的方法,那麼這就是一個觀察者模式的流程