web服務(wù)器

1.1 回顧網(wǎng)絡(luò)編程


1.2 http協(xié)議介紹

HTTP是Hyper Text Transfer Protocol(超文本傳輸協(xié)議)的縮寫棉钧。它的發(fā)展是萬維網(wǎng)協(xié)會(World Wide Web Consortium)和Internet工作小組IETF(Internet Engineering Task Force)合作的結(jié)果,(他們)最終發(fā)布了一系列的RFC涕蚤,RFC 1945定義了HTTP/1.0版本宪卿。其中最著名的就是RFC 2616。RFC 2616定義了今天普遍使用的一個版本——HTTP 1.1万栅。

HTTP協(xié)議(HyperText Transfer Protocol佑钾,超文本傳輸協(xié)議)是用于從WWW服務(wù)器傳輸超文本到本地瀏覽器的傳送協(xié)議。它可以使瀏覽器更加高效申钩,使網(wǎng)絡(luò)傳輸減少次绘。它不僅保證計算機正確快速地傳輸超文本文檔,還確定傳輸文檔中的哪一部分撒遣,以及哪部分內(nèi)容首先顯示(如文本先于圖形)等邮偎。

HTTP是一個基于TCP/IP通信協(xié)議來傳遞數(shù)據(jù)(HTML文件,圖片文件,查詢結(jié)果等)。

HTTP是一個應(yīng)用層協(xié)議义黎,由請求和響應(yīng)構(gòu)成禾进,是一個標(biāo)準(zhǔn)的客戶端服務(wù)器模型。HTTP是一個無狀態(tài)的協(xié)議廉涕。

HTTP協(xié)議永遠都是客戶端發(fā)起請求泻云,服務(wù)器回送響應(yīng)。見下圖:


這樣就限制了使用HTTP協(xié)議狐蜕,無法實現(xiàn)在客戶端沒有發(fā)起請求的時候宠纯,服務(wù)器將消息推送給客戶端。

HTTP協(xié)議是一個無狀態(tài)的協(xié)議层释,同一個客戶端的這次請求和上次請求是沒有對應(yīng)關(guān)系婆瓜。

1.3 使用谷歌或者火狐瀏覽器分析

在Web應(yīng)用中,服務(wù)器把網(wǎng)頁傳給瀏覽器,實際上就是把網(wǎng)頁的HTML代碼發(fā)送給瀏覽器廉白,讓瀏覽器顯示出來个初。而瀏覽器和服務(wù)器之間的傳輸協(xié)議是HTTP,所以:

·HTML是一種用來定義網(wǎng)頁的文本猴蹂,會HTML院溺,就可以編寫網(wǎng)頁;

·HTTP是在網(wǎng)絡(luò)上傳輸HTML的協(xié)議磅轻,用于瀏覽器和服務(wù)器的通信珍逸。

Chrome瀏覽器提供了一套完整地調(diào)試工具,非常適合Web開發(fā)瓢省。

安裝好Chrome瀏覽器后弄息,打開Chrome,在菜單中選擇“視圖”勤婚,“開發(fā)者”摹量,“開發(fā)者工具”,就可以顯示開發(fā)者工具:


說明

·Elements顯示網(wǎng)頁的結(jié)構(gòu)

·Network顯示瀏覽器和服務(wù)器的通信

我們點Network馒胆,確保第一個小紅燈亮著缨称,Chrome就會記錄所有瀏覽器和服務(wù)器之間的通信:


1.4 http協(xié)議分析

當(dāng)我們在地址欄輸入www.sina.com時,瀏覽器將顯示新浪的首頁祝迂。在這個過程中睦尽,瀏覽器都干了哪些事情呢?通過Network的記錄型雳,我們就可以知道当凡。在Network中,找到www.sina.com那條記錄纠俭,點擊沿量,右側(cè)將顯示Request Headers,點擊右側(cè)的view source冤荆,我們就可以看到瀏覽器發(fā)給新浪服務(wù)器的請求:

1.5瀏覽器請求



說明

最主要的頭兩行分析如下朴则,第一行:

GET / HTTP/1.1

GET表示一個讀取請求,將從服務(wù)器獲得網(wǎng)頁數(shù)據(jù)钓简,/表示URL的路徑乌妒,URL總是以/開頭,/就表示首頁外邓,最后的HTTP/1.1指示采用的HTTP協(xié)議版本是1.1撤蚊。目前HTTP協(xié)議的版本就是1.1,但是大部分服務(wù)器也支持1.0版本损话,主要區(qū)別在于1.1版本允許多個HTTP請求復(fù)用一個TCP連接拴魄,以加快傳輸速度。

從第二行開始,每一行都類似于Xxx: abcdefg:

Host: www.sina.com

表示請求的域名是www.sina.com匹中。如果一臺服務(wù)器有多個網(wǎng)站,服務(wù)器就需要通過Host來區(qū)分瀏覽器請求的是哪個網(wǎng)站豪诲。

說明


我們可以跟數(shù)據(jù)庫的CRUD增刪改查操作對應(yīng)起來:

1.CREATE:PUT

2.READ:GET

3.UPDATE:POST

DELETE:DELETE

1.6 服務(wù)器響應(yīng)

繼續(xù)往下找到Response Headers顶捷,點擊view source,顯示服務(wù)器返回的原始響應(yīng)數(shù)據(jù):


HTTP響應(yīng)分為Header和Body兩部分(Body是可選項)屎篱,我們在Network中看到的Header最重要的幾行如下:

HTTP/1.1 200 OK

200表示一個成功的響應(yīng)服赎,后面的OK是說明。

如果返回的不是200交播,那么往往有其他的功能重虑,例如

·失敗的響應(yīng)有404 Not Found:網(wǎng)頁不存在

·500 Internal Server Error:服務(wù)器內(nèi)部出錯

·...等等...

詳情請點擊HTTP狀態(tài)碼.jpg

Content-Type: text/html

Content-Type指示響應(yīng)的內(nèi)容,這里是text/html表示HTML網(wǎng)頁秦士。

請注意缺厉,瀏覽器就是依靠Content-Type來判斷響應(yīng)的內(nèi)容是網(wǎng)頁還是圖片,是視頻還是音樂隧土。瀏覽器并不靠URL來判斷響應(yīng)的內(nèi)容提针,所以,即使URL是http://www.baidu.com/meimei.jpg曹傀,它也不一定就是圖片辐脖。

HTTP響應(yīng)的Body就是HTML源碼,我們在菜單欄選擇“視圖”皆愉,“開發(fā)者”嗜价,“查看網(wǎng)頁源碼”就可以在瀏覽器中直接查看HTML源碼:


瀏覽器解析過程

當(dāng)瀏覽器讀取到新浪首頁的HTML源碼后,它會解析HTML幕庐,顯示頁面久锥,然后,根據(jù)HTML里面的各種鏈接翔脱,再發(fā)送HTTP請求給新浪服務(wù)器奴拦,拿到相應(yīng)的圖片、視頻届吁、Flash错妖、JavaScript腳本、CSS等各種資源疚沐,最終顯示出一個完整的頁面暂氯。所以我們在Network下面能看到很多額外的HTTP請求。


1.7 總結(jié)

1.7.1 請求流程

跟蹤了新浪的首頁亮蛔,我們來總結(jié)一下HTTP請求的流程:

步驟1:瀏覽器首先向服務(wù)器發(fā)送HTTP請求痴施,請求包括:

方法:GET還是POST,GET僅請求資源,POST會附帶用戶數(shù)據(jù);

路徑:/full/url/path动知;

域名:由Host頭指定:Host: www.sina.com

以及其他相關(guān)的Header明垢;

如果是POST,那么請求還包括一個Body厘惦,包含用戶數(shù)據(jù)

步驟2:服務(wù)器向瀏覽器返回HTTP響應(yīng),響應(yīng)包括:

響應(yīng)代碼:200表示成功哩簿,3xx表示重定向宵蕉,4xx表示客戶端發(fā)送的請求有錯誤,5xx表示服務(wù)器端處理時發(fā)生了錯誤节榜;

響應(yīng)類型:由Content-Type指定羡玛;

以及其他相關(guān)的Header;

通常服務(wù)器的HTTP響應(yīng)會攜帶內(nèi)容宗苍,也就是有一個Body稼稿,包含響應(yīng)的內(nèi)容,網(wǎng)頁的HTML源碼就在Body中浓若。

步驟3:如果瀏覽器還需要繼續(xù)向服務(wù)器請求其他資源渺杉,比如圖片,就再次發(fā)出HTTP請求挪钓,重復(fù)步驟1是越、2。

Web采用的HTTP協(xié)議采用了非常簡單的請求-響應(yīng)模式碌上,從而大大簡化了開發(fā)倚评。當(dāng)我們編寫一個頁面時,我們只需要在HTTP請求中把HTML發(fā)送出去馏予,不需要考慮如何附帶圖片天梧、視頻等,瀏覽器如果需要請求圖片和視頻霞丧,它會發(fā)送另一個HTTP請求呢岗,因此,一個HTTP請求只處理一個資源(此時就可以理解為TCP協(xié)議中的短連接蛹尝,每個鏈接只獲取一個資源后豫,如需要多個就需要建立多個鏈接)

HTTP協(xié)議同時具備極強的擴展性,雖然瀏覽器請求的是http://www.sina.com的首頁突那,但是新浪在HTML中可以鏈入其他服務(wù)器的資源挫酿,比如,從而將請求壓力分散到各個服務(wù)器上愕难,并且早龟,一個站點可以鏈接到其他站點惫霸,無數(shù)個站點互相鏈接起來,就形成了World Wide Web葱弟,簡稱WWW壹店。

e7 a??D? ?

1.7.2 http格式



每個HTTP請求和響應(yīng)都遵循相同的格式,一個HTTP包含Header和Body兩部分芝加,其中Body是可選的茫打。

HTTP協(xié)議是一種文本協(xié)議,所以妖混,它的格式也非常簡單。

HTTP GET請求的格式:

GET /path HTTP/1.1

Header1: Value1

Header2: Value2

Header3: Value3

每個Header一行一個轮洋,換行符是\r\n制市。

HTTP POST請求的格式:

POST /path HTTP/1.1

Header1: Value1

Header2: Value2

Header3: Value3

body data goes here...

當(dāng)遇到連續(xù)兩個\r\n時,Header部分結(jié)束弊予,后面的數(shù)據(jù)全部是Body祥楣。

HTTP響應(yīng)的格式:

200 OK

Header1: Value1

Header2: Value2

Header3: Value3

body data goes here...

HTTP響應(yīng)如果包含body,也是通過\r\n\r\n來分隔的汉柒。

請再次注意误褪,Body的數(shù)據(jù)類型由Content-Type頭來確定,如果是網(wǎng)頁碾褂,Body就是文本兽间,如果是圖片,Body就是圖片的二進制數(shù)據(jù)正塌。

當(dāng)存在Content-Encoding時嘀略,Body數(shù)據(jù)是被壓縮的,最常見的壓縮方式是gzip乓诽,所以帜羊,看到Content-Encoding: gzip時,需要將Body數(shù)據(jù)先解壓縮鸠天,才能得到真正的數(shù)據(jù)讼育。壓縮的目的在于減少Body的大小,加快網(wǎng)絡(luò)傳輸稠集。

1.8 web靜態(tài)服務(wù)器

1.8.1 顯示靜態(tài)頁面

import socket

from multiprocessing import Process

def handleClient(clientSocket):

'用一個新的進程奶段,為一個客戶端進行服務(wù)'

recvData = clientSocket.recv(2014)

requestHeaderLines = recvData.splitlines()

for line in requestHeaderLines:

print(line.decode('utf-8'))

responseHeaderLines = "HTTP/1.1 200 OK\r\n"

responseHeaderLines += "Server:laowang\r\n"

responseHeaderLines += "\r\n"

responseBody = "hello world"

response = responseHeaderLines + responseBody

clientSocket.send(bytes(response,'gbk'))

clientSocket.close()

def main():

'作為程序的主控制入口'

serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

serverSocket.bind(("", 8000))

serverSocket.listen(10)

while True:

clientSocket,clientAddr = serverSocket.accept()

clientP = Process(target = handleClient, args = (clientSocket,))

clientP.start()

clientSocket.close()

if __name__ == '__main__':

main()

客戶端瀏覽器


服務(wù)端


1.9顯示需要的頁面

參考代碼

import socket

import re

from multiprocessing import Process

#設(shè)置靜態(tài)文件根目錄

HTML_ROOT_DIR = "./html"

def handle_client(client_socket):

"""處理客戶端請求"""

#獲取客戶端請求數(shù)據(jù)

request_data = client_socket.recv(1024)

print("request data:", request_data)

request_lines = request_data.splitlines()

for line in request_lines:

print(line)

#解析請求報文

# 'GET / HTTP/1.1'

request_start_line = request_lines[0].decode('utf-8')

#提取用戶請求的文件名

file_name = re.match(r"\w+ +(/[^ ]*) ", request_start_line).group(1)

if "/" == file_name:

file_name = "/index.html"

#打開文件,讀取內(nèi)容

try:

file = None

file = open(HTML_ROOT_DIR + file_name, "rb")

file_data = file.read()

#構(gòu)造響應(yīng)數(shù)據(jù)

response_start_line = "HTTP/1.1 200 OK\r\n"

response_headers = "Server: My server\r\n"

response_body = file_data.decode("utf-8")

except FileNotFoundError:

response_start_line = "HTTP/1.1 404 Not Found\r\n"

response_headers = "Server: My server\r\n"

response_body = "The file is not found!"

finally:

if file and (not file.closed):

file.close()

response = response_start_line + response_headers + "\r\n" + response_body

print("response data:", response)

#向客戶端返回響應(yīng)數(shù)據(jù)

client_socket.send(bytes(response, "utf-8"))

#關(guān)閉客戶端連接

client_socket.close()

def main():

'作為程序的主控制入口'

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server_socket.bind(("", 8000))

server_socket.listen(128)

while True:

client_socket, client_address = server_socket.accept()

# print("[%s, %s]用戶連接上了" % (client_address[0],client_address[1]))

print("[%s, %s]用戶連接上了" % client_address)

handle_client_process = Process(target=handle_client, args=(client_socket,))

handle_client_process.start()

client_socket.close()

if __name__ == "__main__":

main()

客戶瀏覽器





最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末巍杈,一起剝皮案震驚了整個濱河市忧饭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌筷畦,老刑警劉巖词裤,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刺洒,死亡現(xiàn)場離奇詭異,居然都是意外死亡吼砂,警方通過查閱死者的電腦和手機逆航,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渔肩,“玉大人因俐,你說我怎么就攤上這事≈苜耍” “怎么了抹剩?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蓉坎。 經(jīng)常有香客問我澳眷,道長,這世上最難降的妖魔是什么蛉艾? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任钳踊,我火速辦了婚禮,結(jié)果婚禮上勿侯,老公的妹妹穿的比我還像新娘拓瞪。我一直安慰自己,他們只是感情好助琐,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布祭埂。 她就那樣靜靜地躺著,像睡著了一般弓柱。 火紅的嫁衣襯著肌膚如雪沟堡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天矢空,我揣著相機與錄音航罗,去河邊找鬼。 笑死屁药,一個胖子當(dāng)著我的面吹牛粥血,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酿箭,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼复亏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缭嫡?” 一聲冷哼從身側(cè)響起缔御,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妇蛀,沒想到半個月后耕突,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笤成,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年眷茁,在試婚紗的時候發(fā)現(xiàn)自己被綠了炕泳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡上祈,死狀恐怖培遵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情登刺,我是刑警寧澤籽腕,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站纸俭,受9級特大地震影響节仿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掉蔬,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望矾瘾。 院中可真熱鬧女轿,春花似錦、人聲如沸壕翩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽放妈。三九已至北救,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芜抒,已是汗流浹背珍策。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宅倒,地道東北人攘宙。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像拐迁,于是被迫代替她去往敵國和親蹭劈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容