版權(quán)聲明:本文為作者原創(chuàng)文章,可以隨意轉(zhuǎn)載,但必須在明確位置標(biāo)明出處?。?!
tips:本基礎(chǔ)系列旨在以爬蟲帶大家入門Python語言
上一篇文章介紹了HTTP協(xié)議,相信讀者對(duì)HTTP協(xié)議也有了一個(gè)基本的了解,但這還不夠,光了解它并不代表你能夠使用它,就像練習(xí)武林秘訣一樣,光知道口訣是不行的,還要反復(fù)的去聯(lián)系,去體會(huì)才能融會(huì)貫通,所以我們擁有了HTTP協(xié)議口訣后,要做的就是去練習(xí)它了,本章將會(huì)通過原生的socket套接字去實(shí)現(xiàn)HTTP請(qǐng)求以加深如協(xié)議的理解。
socket套接字
套接字是計(jì)算機(jī)網(wǎng)絡(luò)數(shù)據(jù)結(jié)構(gòu),它體現(xiàn)了“通信端點(diǎn)”的概念,在任何類型的通信開始之前,網(wǎng)絡(luò)應(yīng)用程序都必須創(chuàng)建套接字,你可以把她當(dāng)作老式的電話線,要讓電話可用那必須先得插上和外界通信的電話線。套接字的起源可以追溯到20 世紀(jì)70 年代,它是加利福尼亞大學(xué)的伯克利版本UNIX(稱為BSD UNIX)的一部分。因此,有時(shí)你可能會(huì)聽過將套接字稱為伯克利套接字或BSD 套接字。套接字最初是為同一主機(jī)上的應(yīng)用程序所創(chuàng)建,使得主機(jī)上運(yùn)行的一個(gè)程序(又名一個(gè)進(jìn)程)與另一個(gè)運(yùn)行的程序進(jìn)行通信。這就是所謂的進(jìn)程間通信(Inter Process Communication,IPC)。有兩種類型的套接字:基于文件的和面向網(wǎng)絡(luò)的。基于文件的家族是AF_UNIX;AF_NETLINK、AF_TIPC、AF_INET家族都是基于網(wǎng)絡(luò)的。
socket模塊
要使用網(wǎng)絡(luò)編程就必須的用到socket模塊了,這個(gè)模塊是 Python 的標(biāo)準(zhǔn)庫模塊,可以直接導(dǎo)入使用,網(wǎng)絡(luò)傳輸有兩種模式,一種是可靠傳輸,也就是使用TCP協(xié)議,一種是不可靠傳輸,使用UDP協(xié)議;什么是可靠傳輸呢,可靠傳輸是指要確保我發(fā)給對(duì)方的數(shù)據(jù),對(duì)方一定能收到, 它常用在文件傳輸。UDP為不可以傳輸,是指我只管把數(shù)據(jù)發(fā)給你,至于你有沒有收到我并不關(guān)心,所以UDP協(xié)議常用在視頻傳輸,實(shí)時(shí)通信等方面,對(duì)于視頻傳輸就算少個(gè)3,4幀數(shù)據(jù)我們?nèi)搜凼强床怀鰜淼?,TCP、UDP都是傳輸層協(xié)議,它們都需要通過IP(網(wǎng)絡(luò)層)封裝后才能在網(wǎng)絡(luò)中傳輸,TCP比UPD傳輸速率慢,因?yàn)門CP有「三次握手」,「四次揮手」。
| 屬性 | TCP | UDP |
|---|---|---|
| 連接性 | 面向連接 | 面向無連接 |
| 可靠性 | 可靠 | 不可靠 |
| 傳輸效率 | 慢 | 快 |
套接字對(duì)象的內(nèi)置方法
網(wǎng)絡(luò)編程的第一步就是創(chuàng)建一個(gè)socket套接字,它返回一個(gè)套接字對(duì)象,該對(duì)象有如下方法

網(wǎng)絡(luò)編程流程
在編寫代碼之前首先要了解客戶端和服務(wù)端的交互流程,這個(gè)流程一定要記得滾瓜爛熟,最好的辦法就是多寫幾遍,我剛開始學(xué)網(wǎng)絡(luò)編程就是用的這種辦法。TCP和UDP的交互流程如下
-
TCP協(xié)議模型
- 服務(wù)端:
- 創(chuàng)建套接字(socket)
- 綁定端口(bind)
- 監(jiān)聽端口(listen)
- 接受連接(accept)無限循環(huán)等待客戶端的連接請(qǐng)求
- 接收/發(fā)送消息(recv/send)
- 關(guān)閉套接字
- 客戶端:
- 創(chuàng)建套接字(socket)
- 連接服務(wù)端(connect)
- 發(fā)送/接收消息(send/recv)
- 關(guān)閉套接字
- 服務(wù)端:
-
UDP的交互流程如下:
- 服務(wù)端:
- 創(chuàng)建套接字(socket)
- 綁定端口(bind)
- 接收/發(fā)送消息(recvfrom/sendto)
- 關(guān)閉套接字
- 客戶端:
- 創(chuàng)建套接字(socket)
- 連接服務(wù)端(connect)
- 發(fā)送/接收消息(send/recv)
- 關(guān)閉套接字
socketserver模塊
該模塊是一個(gè)高級(jí)的抽象模塊,它的目標(biāo)是簡化很多樣板代碼,就是創(chuàng)建網(wǎng)絡(luò)客戶端和服務(wù)器所必需的代碼,所以該模塊只是封裝了一些原生套接字的的功能,你查看該模塊的源碼肯定會(huì)發(fā)現(xiàn)其實(shí)它還是用的socket,所以在你剛接觸網(wǎng)絡(luò)編程的時(shí)候一定要使用原生的套接字,讓自己掌握客戶端和服務(wù)端的交互流程,當(dāng)你覺得你已經(jīng)用的很熟了的時(shí)候你可以考慮使用更高級(jí)的模塊,初學(xué)的時(shí)候建議使用原生的套接字,accept默認(rèn)是阻塞的,只有等待客戶端的連接請(qǐng)求了才會(huì)返回。有阻塞肯定就有異步,所以讀者可以去了解了解異步套接字怎么實(shí)現(xiàn),異步套接字的實(shí)現(xiàn)可以去了解select模塊, 再深入一點(diǎn)就是去讀TCP/IP協(xié)議詳解。
Request請(qǐng)求格式

Response應(yīng)答格式

實(shí)戰(zhàn)
光說不練都是假把式,下面將會(huì)使用原生的套接字實(shí)現(xiàn)http協(xié)議的幾個(gè)方法
- GET方法
from socket import *
# 創(chuàng)建套接字
tcp_socket = socket(AF_INET, SOCK_STREAM)
# 連接服務(wù)器
tcp_socket.connect(('www.baidu.com', 80))
request_str = '''GET /home/news/data/newspage HTTP/1.1\r\n\
Host:www.baidu.com\r\n\
Connection:keep-alive\r\n\
Accept-Encoding:gzip, deflate, br\r\n
Accept-Language:en,zh-CN;q=0.8,zh;q=0.6\r\n
User_Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36\r\n\r\n'''
tcp_socket.send(bytes(request_str.encode('utf-8')))
response_str = tcp_socket.recv(4096)
print(response_str)
- 返回結(jié)果
HTTP/1.1 200 OK
Date: Wed, 15 Nov 2017 06:59:19 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: Keep-Alive
Vary: Accept-Encoding
Cache-Control: private
Expires: Wed, 15 Nov 2017 06:59:19 GMT
tracecode: 35597275360655541002111514
Set-Cookie: BAIDUID=800F3E63D821D767A0F99B52BF9C82A4:FG=1; expires=Thu, 15-Nov-18 06:59:19 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Content-Encoding: gzip
Server: BWS/1.0
- POST方法
from socket import *
# 創(chuàng)建套接字
tcp_socket = socket(AF_INET, SOCK_STREAM)
# 連接服務(wù)器
tcp_socket.connect(('www.baidu.com', 80))
request_str = '''POST /home/news/data/newspage HTTP/1.1\r\n\
Host:www.baidu.com\r\n\
Connection:keep-alive\r\n\
Accept-Encoding:gzip, deflate, br\r\n
Accept-Language:en,zh-CN;q=0.8,zh;q=0.6\r\n
User_Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36\r\n\r\n'''
tcp_socket.send(bytes(request_str.encode('utf-8')))
response_str = tcp_socket.recv(4096)
print(response_str)
- 返回結(jié)果
HTTP/1.1 200 OK
Date: Wed, 15 Nov 2017 07:27:41 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: Keep-Alive
Vary: Accept-Encoding
Cache-Control: private
Expires: Wed, 15 Nov 2017 07:27:41 GMT
tracecode: 16618310650351194890111515
Set-Cookie: BAIDUID=12E8E5D7F713B721254540A39F83EF37:FG=1; expires=Thu, 15-Nov-18 07:27:41 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Content-Encoding: gzip
Server: BWS/1.0
- OPTIONS方法
from socket import *
# 創(chuàng)建套接字
tcp_socket = socket(AF_INET, SOCK_STREAM)
# 連接服務(wù)器
tcp_socket.connect(('www.baidu.com', 80))
request_str = '''OPTIONS http://www.baidu.com HTTP/1.1\r\n\
Host:www.baidu.com\r\n\
Connection:keep-alive\r\n\
Accept-Encoding:gzip, deflate, br\r\n
Accept-Language:en,zh-CN;q=0.8,zh;q=0.6\r\n
User_Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36\r\n\r\n'''
tcp_socket.send(bytes(request_str.encode('utf-8')))
response_str = tcp_socket.recv(4096)
print(response_str)
- 返回結(jié)果
HTTP/1.1 200 OK
Date: Wed, 15 Nov 2017 07:34:23 GMT
Server: Apache
P3P: CP=" OTI DSP COR IVA OUR IND COM "
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Set-Cookie: BAIDUID=B709AAC9A337A10E7C13EB1C84696D10:FG=1; expires=Thu, 15-Nov-18 07:34:23 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
Set-Cookie: BAIDUID=B709AAC9A337A10EF3C3565FCF06D220:FG=1; expires=Thu, 15-Nov-18 07:34:23 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
Allow: GET,HEAD,POST,OPTIONS,TRACE
Cache-Control: max-age=1
Expires: Wed, 15 Nov 2017 07:34:24 GMT
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 20
Connection: Keep-Alive
Content-Type: text/html
從返回結(jié)果中我看可以看到百度服務(wù)器不支持PUT,DELETE方法,想想也知道為撒啊,要是支持了這兩個(gè)方法那還不得亂套了,你可以隨便想他的服務(wù)器上傳文件,也可以刪除服務(wù)器上的文件,這得有多恐怖是吧。TRACE方法也可以自己去試試,不過我測試過這個(gè)方法,服務(wù)器并沒有返回任何應(yīng)答給我。
okay,本章就到這里結(jié)束了,學(xué)習(xí)一個(gè)協(xié)議的時(shí)候最好的理解辦法就是親自動(dòng)手去實(shí)踐一下。一定要養(yǎng)成這樣的習(xí)慣,對(duì)于肯定大有裨益。