python(十四)網絡編程

1,網絡編程,TCP/IP協議,端口簡介
html

網絡編程,也就是經過某種手段實現兩臺電腦之間互相通訊。再詳細一點就是,兩臺電腦之間的通訊,其本質是計算機內部兩個進程間的通訊。好比說QQ,在兩臺不一樣的電腦上,啓動一個QQ程序就會在當前電腦上開啓一個通訊的通道,這個通道都是進程,這個進程在電腦上監聽着一個位置,等待接受消息和發送消息,一樣的另一臺電腦上的QQ也是如此,這樣就能夠實現通訊。python

那爲了可以使得發送出去的數據能夠準確的找到對應接受方的電腦,並且這種動做必需要是全球統一的,因而就制定了一套規範。那計算機只要按這個規範來呢,就能實現相互通訊,這個規範就是咱們講的「協議」!web

計算機之間的協議有不少,其中最重要的就是咱們熟知的TCP/IP協議。
編程

因爲在兩臺電腦之間進行通訊的時候,必須知道對方的地址,就像你要給誰寫信或者寄件的時候必須寫清楚接收方的地址同樣。那麼IP協議就負責把你要發送的數據準確的找到接受方,固然了,你必須得告訴它接受方的地址。IP協議把數據拆分紅IP數據包,一塊一塊的發送給接受方,可是這裏就會產生一個問題,因爲IP協議發送出去的數據塊,不必定是按順序到達,也不能保證必定能到達,這樣發送出去的數據就不必定會「安全」,並且數據也不必定會完整!
安全

因而就產生了TCP和UDP協議。服務器

TCP和UDP協議都是基於IP協議之上的。網絡

TCP協議是可靠的協議,由於它會保證發送方的數據是按順序到達,同時也保證數據塊不丟失,若是中途丟失了那麼就會自動重發。socket

UDP協議是不可靠的協議,由於它只會幫你把數據包發出去,而後至於能不能到達,這它就無論了。學習

那麼有了安全的TCP爲何還須要不安全的UDP呢?是由於在有些狀況下,咱們須要數據發送的速度而不在意數據是否完整,這樣因爲UDP並不保證數據包的完整性那麼它的速度相對TCP來講會快一些。spa

那麼是什麼是端口呢?

好比說,A電腦上的QQ要和B電腦上的QQ進行通訊。首先光知道對方的IP地址還不夠,由於當數據準確到達對方電腦上的時候,還得明確這個數據是要被誰接收的,是被QQ仍是電腦上其它的程序。

這樣,端口就是用來區分一臺電腦上不一樣的應用程序的!比如,大家住同一個村,可是大家之間還須要不一樣的門牌號來區分你和別人家!

2,基於TCP協議的網絡編程

網絡編程迴歸到程序中的實現是以套接字來描述的,也就是咱們說的 Socket 編程。在 python 中經過 socket 模塊來實現網絡編程。

經過上面的描述,咱們也知道,在 Socket 編程中存在「服務器端」和「客戶端」,也就是發送方和接受方。

那麼在「服務器端」須要作的就是:先打開一個 socket 通道,而後綁定對應的 IP 和端口,而後就開始監聽等待着「客戶端」的鏈接。當有客戶端鏈接進來以後,就能夠從其中讀取數據或者向裏面發送數據了。最終,當整個通訊結束以後就能夠關閉鏈接了。

相對於「服務器端」,客戶端作的事情就顯然少了不少,它只須要:打開一個 socket 通道,而後根據給定的 IP 和 端口,鏈接到「服務器端」,而後一樣也能夠從裏面來讀取和發送數據,在最後通訊結束以後也一樣須要關閉鏈接。

下面的例子咱們先寫一個基本的「服務器」程序,當啓動它的時候,它就開始等待着「客戶端」的鏈接,代碼以下:

接着,咱們就能夠繼續編寫一個「客戶端」,當再啓動它的時候就會向「服務器端」發送一些數據,而且能夠接收從「服務器」端返回回來的數據,以下:

同時,「服務器端」就會有以下的響應:

你看,其實網絡編程也沒有想象中那麼神奇,不是嗎?

在上面的代碼中有這麼一行:

socket.socket(socket.AF_INET, socket.SOCK_STREAM)

這裏的兩個參數,分別指定了打開一個 socket 通道的時候採用的 IP 協議是那個版本和創建的 socket 通道是屬於TCP型仍是UDP型。對應的 「socket.AF_INET」是指使用 IP v4 的協議,而「socket.SOCK_STREAM」對應的則是 TCP 協議。

3,基於UDP協議的網絡編程

和 TCP 相似,建立一個基於 UDP 協議的服務器端也是須要先打開一個 socket 通道,而後和客戶端進行通訊,可是這裏和TCP方式不一樣的是,UDP協議的服務器端並不須要去「監聽」客戶端的鏈接。

下面是一個簡單的 UDP 服務器端程序:

從上面的例子能夠看到,基於 UDP 的服務器端程序,在打開一個 socket 通道以後只須要綁定本機對應的 IP 和 端口以後就可使用 「recvfrom」方法來接收數據了,當須要寫數據的時候則是直接調用「sendto」方法,把數據直接寫入到指定的「客戶端」中!

有了上面的 服務器,咱們仍是須要一個簡單的 客戶端,就像是這樣:

當啓動這個客戶端的時候,服務器端的響應以下:

4,一個簡單的案例

這個案例也正是我以前寫的時候碰到的一個問題,分享一下。

多數狀況下,網絡編程可使咱們模擬發送請求去獲取遠端web上面的數據,而後對獲得的數據作出分析取出咱們真正關心的數據,最後把這些數據作處理,好比說存起來,這就是一般人們說的採集。

那既然咱們學習了 socket 編程,就必定能夠模擬請求,而後獲取到遠端web的數據,那麼下面的案例就是咱們能夠模擬請求開源中國站,而後針對返回的數據,咱們把數據存儲到一個 .html 的本地文件中,這樣在本地咱們就能夠查看開源中國的首頁了,固然了,這個是暫時性的!

咱們的基本思路是:先建立一個 socket 通道,而後鏈接上開源中國的主戰,而後模擬發送一個 GET 請求,而後循環的去讀取返回回來的數據,最後對數據作處理,這裏是把它存儲到一個本地文件中。

對於模擬發送請求的程序,若是你仍是不理解上面的程序,那麼你可能須要先去了解一些 HTTP 協議的簡單知識。

我要解釋的問題是:

當我採用 HTTP 1.1 協議的時候,若是不帶 「Connection:Close」頭信息,那麼後續的 循環讀取 數據就會陷入死循環。這是由於 HTTP 1.1 協議中,默認開啓了長鏈接,這樣雖然你已經讀取完了數據,可是鏈接尚未關閉,這樣就致使了死循環的發生。那麼解決方案也比較簡單,就是在請求的時候主動設置頭信息來關閉長鏈接,也就是加上頭:Connection:Close

----------------------------------------------分割線----------------------------------------------------

一個問題未獲得驗證,所以須要等驗證經過再開始寫了 ╮(╯▽╰)╭

相關文章
相關標籤/搜索