聰哥哥教你學Python之網路程式設計
網路程式設計,又稱Socket程式設計。
說到網路程式設計,大家都想起一個東西,那就是TCP/IP。
絕大多數程式語言都有對TCP/IP的操作API。
聰哥哥我今天主要圍繞兩個方面談談網路程式設計。一個TCP,另外一個就是UDP。
關於TCP和UDP,它們無論是在Java,還是在Python,都算是一個面試常考題。
有人會問,什麼是TCP?什麼是UDP?TCP和UDP的區別是什麼?
問題一個一個來回答。
問:什麼是TCP?
答:
引用百度百科:
TCP(Transmission Control Protocol 傳輸控制協議)是一種面向連線的、可靠的、基於位元組流的
應用層向TCP層傳送用於網間傳輸的、用8位位元組表示的資料流,然後TCP把資料流分割槽成適當長度的報文段(通常受該計算機連線的網路的資料鏈路層的最大傳輸單元( MTU)的限制)。之後TCP把結果包傳給IP層,由它來通過網路將包傳送給接收端實體的TCP層。TCP為了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認(ACK);如果傳送端實體在合理的往返時延(
問:什麼是UDP?
答:
引用百度百科:
UDP 是User Datagram Protocol的簡稱, 中文名是使用者資料報協議,是OSI(Open System Interconnection,開放式系統互聯) 參考模型中一種無連線的傳輸層協議,提供面向事務的簡單不可靠資訊傳送服務,IETF RFC 768是UDP的正式規範。UDP在IP報文的協議號是17。
與所熟知的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。