聚沙成塔--爬蟲系列(十八)(原生socket(套接字)實(shí)現(xiàn)HTTP請(qǐng)求)

版權(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ù)端:
      1. 創(chuàng)建套接字(socket)
      2. 綁定端口(bind)
      3. 監(jiān)聽端口(listen)
      4. 接受連接(accept)無限循環(huán)等待客戶端的連接請(qǐng)求
      5. 接收/發(fā)送消息(recv/send)
      6. 關(guān)閉套接字
    • 客戶端:
      1. 創(chuàng)建套接字(socket)
      2. 連接服務(wù)端(connect)
      3. 發(fā)送/接收消息(send/recv)
      4. 關(guān)閉套接字
  • UDP的交互流程如下
    • 服務(wù)端:
    1. 創(chuàng)建套接字(socket)
    2. 綁定端口(bind)
    3. 接收/發(fā)送消息(recvfrom/sendto)
    4. 關(guān)閉套接字
    • 客戶端:
      1. 創(chuàng)建套接字(socket)
      2. 連接服務(wù)端(connect)
      3. 發(fā)送/接收消息(send/recv)
      4. 關(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)求格式

Request請(qǐng)求格式

Response應(yī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ì)于肯定大有裨益。


歡迎關(guān)注我:「愛做飯的老謝」,老謝一直在努力...

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容