1. 程式人生 > >聰哥哥教你學Python之網路程式設計

聰哥哥教你學Python之網路程式設計

網路程式設計,又稱Socket程式設計。

說到網路程式設計,大家都想起一個東西,那就是TCP/IP。

絕大多數程式語言都有對TCP/IP的操作API。

聰哥哥我今天主要圍繞兩個方面談談網路程式設計。一個TCP,另外一個就是UDP。

關於TCP和UDP,它們無論是在Java,還是在Python,都算是一個面試常考題。

有人會問,什麼是TCP?什麼是UDP?TCP和UDP的區別是什麼?

問題一個一個來回答。

問:什麼是TCP?

答:

引用百度百科:

TCP(Transmission Control Protocol 傳輸控制協議)是一種面向連線的、可靠的、基於位元組流的

傳輸層通訊協議,由IETF的RFC 793定義。在簡化的計算機網路OSI模型中,它完成第四層傳輸層所指定的功能,使用者資料報協議(UDP)是同一層內另一個重要的傳輸協議。在因特網協議族(Internet protocol suite)中,TCP層是位於IP層之上,應用層之下的中間層。不同主機的應用層之間經常需要可靠的、像管道一樣的連線,但是IP層不提供這樣的流機制,而是提供不可靠的包交換。 

應用層向TCP層傳送用於網間傳輸的、用8位位元組表示的資料流,然後TCP把資料流分割槽成適當長度的報文段(通常受該計算機連線的網路的資料鏈路層的最大傳輸單元( MTU)的限制)。之後TCP把結果包傳給IP層,由它來通過網路將包傳送給接收端實體的TCP層。TCP為了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認(ACK);如果傳送端實體在合理的往返時延(

RTT)內未收到確認,那麼對應的資料包就被假設為已丟失將會被進行重傳。TCP用一個校驗和函式來檢驗資料是否有錯誤;在傳送和接收時都要計算校驗和。 

 

問:什麼是UDP?

答:

引用百度百科:

UDP 是User Datagram Protocol的簡稱, 中文名是使用者資料報協議,是OSI(Open System Interconnection,開放式系統互聯) 參考模型中一種無連線的傳輸層協議,提供面向事務的簡單不可靠資訊傳送服務,IETF RFC 768是UDP的正式規範。UDP在IP報文的協議號是17。

UDP協議全稱是使用者資料報協議  

 ,在網路中它與TCP協議一樣用於處理資料包,是一種無連線的協議。在OSI模型中,在第四層——傳輸層,處於IP協議的上一層。UDP有不提供資料包分組、組裝和不能對資料包進行排序的缺點,也就是說,當報文傳送之後,是無法得知其是否安全完整到達的。UDP用來支援那些需要在計算機之間傳輸資料的網路應用。包括網路視訊會議系統在內的眾多的客戶/伺服器模式的網路應用都需要使用UDP協議。UDP協議從問世至今已經被使用了很多年,雖然其最初的光彩已經被一些類似協議所掩蓋,但是即使是在今天UDP仍然不失為一項非常實用和可行的網路傳輸層協議。

與所熟知的TCP(傳輸控制協議)協議一樣,UDP協議直接位於IP(網際協議)協議的頂層。根據OSI(開放系統互連)參考模型,UDP和TCP都屬於傳輸層協議。UDP協議的主要作用是將網路資料流量壓縮成資料包的形式。一個典型的資料包就是一個二進位制資料的傳輸單位。每一個數據包的前8個位元組用來包含報頭資訊,剩餘位元組則用來包含具體的傳輸資料。

 

問:TCP和UDP的區別是什麼?

答:

通過百度百科對比分析,可得出如下結果:

TCP:

優點:可靠 穩定

     TCP的可靠體現在TCP在傳輸資料之前,會有三次握手來建立連線,而且在資料傳遞時,有確認. 視窗. 重傳. 擁塞控制機制,在資料傳完之後,還會斷開來連線用來節約系統資源。

缺點:慢,效率低,佔用系統資源高,易被攻擊

     在傳遞資料之前要先建立連線,這會消耗時間,而且在資料傳遞時,確認機制. 重傳機制. 擁塞機制等都會消耗大量時間,而且要在每臺裝置上維護所有的傳輸連線。然而,每個連線都會佔用系統的CPU,記憶體等硬體資源。因為TCP有確認機制. 三次握手機制,這些也導致TCP容易被利用,實現DOS. DDOS. CC等攻擊。


UDP:

優點:快,比TCP稍微安全點

     UDP沒有TCP擁有的各種機制,是一種無狀態的傳輸協議,所以傳輸資料非常快,沒有TCP的這些機制,被攻擊利用的機會就少一些,但是也無法避免被攻擊。

缺點:不可靠,不穩定

     因為沒有TCP的這些機制,UDP在傳輸資料時,如果網路質量不好,就會很容易丟包,造成資料的缺失。
 

一、TCP

Socket是網路程式設計的一個抽象概念。通常我們用一個Socket表示“打開了一個網路連結”,而開啟一個Socket需要知道目標計算機的IP地址和埠號,再指定協議型別即可。

1.客戶端

大多數連線都是可靠的TCP連線。建立TCP連線時,主動發起連線的叫客戶端,被動響應連線的叫伺服器。

客戶端的百度百科解釋如下:

客戶端(Client)或稱為使用者端,是指與伺服器相對應,為客戶提供本地服務的程式。除了一些只在本地執行的應用程式之外,一般安裝在普通的客戶機上,需要與服務端互相配合執行。因特網發展以後,較常用的使用者端包括瞭如全球資訊網使用的網頁瀏覽器,收寄電子郵件時的電子郵件客戶端,以及即時通訊的客戶端軟體等。對於這一類應用程式,需要網路中有相應的伺服器和服務程式來提供相應的服務,如資料庫服務,電子郵件服務等等,這樣在客戶機和伺服器端,需要建立特定的通訊連線,來保證應用程式的正常執行。

 

舉個例子,當我們在瀏覽器中訪問新浪時,我們自己的計算機就是客戶端,瀏覽器會主動向新浪的伺服器發起連線。如果一切順利,新浪的伺服器接受了我們的連線,一個TCP連線就建立起來的,後面的通訊就是傳送網頁內容了。

示例程式碼:

# -*- coding: utf-8 -*-
# 匯入socket庫:
import socket

# 建立一個socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連線:
s.connect(('www.sina.com.cn', 80))
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
# 接收資料:
buffer = []
while True:
    # 每次最多接收1k位元組:
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)
print(data);
#關閉連線
s.close()

header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))
# 把接收的資料寫入檔案:
with open('sina.html', 'wb') as f:
    f.write(html)

2.服務端

和客戶端程式設計相比,伺服器程式設計就要複雜一些。

伺服器程序首先要繫結一個埠並監聽來自其他客戶端的連線。如果某個客戶端連線過來了,伺服器就與該客戶端建立Socket連線,隨後的通訊就靠這個Socket連線了。

所以,伺服器會開啟固定埠(比如80)監聽,每來一個客戶端連線,就建立該Socket連線。由於伺服器會有大量來自客戶端的連線,所以,伺服器要能夠區分一個Socket連線是和哪個客戶端繫結的。一個Socket依賴4項:伺服器地址、伺服器埠、客戶端地址、客戶端埠來唯一確定一個Socket。

但是伺服器還需要同時響應多個客戶端的請求,所以,每個連線都需要一個新的程序或者新的執行緒來處理,否則,伺服器一次就只能服務一個客戶端了。

 

服務端百度百科的解釋如下:

服務端是為客戶端服務的,服務的內容諸如向客戶端提供資源,儲存客戶端資料。是實現遊戲特色化的重要途徑,也是最直接可以通過遊戲表現出來的技術,比如你要修改某個NPC的引數,重載入後,在遊戲內立刻體現出來。

可測試本地的MySQL伺服器:

# -*- coding: utf-8 -*-
# 匯入socket庫:
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連線:
s.connect(('127.0.0.1', 3306))
# 接收歡迎訊息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 傳送資料:
    s.send(data)
    print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()

 

聰哥哥有話說:

用TCP協議進行Socket程式設計在Python中十分簡單,對於客戶端,要主動連線伺服器的IP和指定埠,對於伺服器,要首先監聽指定埠,然後,對每一個新的連線,建立一個執行緒或程序來處理。通常,伺服器程式會無限執行下去。

同一個埠,被一個Socket綁定了以後,就不能被別的Socket綁定了。

 

二、UDP

TCP是建立可靠連線,並且通訊雙方都可以以流的形式傳送資料。相對TCP,UDP則是面向無連線的協議。

使用UDP協議時,不需要建立連線,只需要知道對方的IP地址和埠號,就可以直接發資料包。但是,能不能到達就不知道了。

雖然用UDP傳輸資料不可靠,但它的優點是和TCP比,速度快,對於不要求可靠到達的資料,就可以使用UDP協議。

示例:

服務端程式碼

# -*- coding: utf-8 -*-
# 匯入socket庫:
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 繫結埠:
s.bind(('127.0.0.1', 9999))
print('Bind UDP on 9999...')
while True:
    # 接收資料:
    data, addr = s.recvfrom(1024)
    print('Received from %s:%s.' % addr)
    s.sendto(b'Hello, %s!' % data, addr)

客戶端程式碼:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 傳送資料:
    s.sendto(data, ('127.0.0.1', 9999))
    # 接收資料:
    print(s.recv(1024).decode('utf-8'))
s.close()

按照步驟執行,先服務端後客戶端。

最後的結果應該是:

聰哥哥有話說:UDP的使用與TCP類似,但是不需要建立連線。此外,伺服器繫結UDP埠和TCP埠互不衝突,也就是說,UDP的9999埠與TCP的9999埠可以各自繫結。

 

小結:

建議不管是大學生還是已經工作有一段時間(一年或者兩年或者兩年以上)的開發者們,都有必要熟讀TCP/IP。