python基礎之Socket套接字詳解
前言
Python語言提供瞭Socket套接字來實現網絡通信。
Python的應用程序通常通過Socket”套接字”向網絡發出請求或者應答網絡請求,使主機間或者一臺計算機上的進程間可以通訊。
服務器和客戶端的源代碼
服務器端
#coding=utf-8 #創建TCP服務器 import socket import time from time import ctime HOST = '127.0.0.1' PORT = 8080 BUFSIZE=1024 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((HOST, PORT)) sock.listen(5) addr=(HOST,PORT) while True: print('waiting for connection...') sock,addr =sock.accept() print('...connected from:',addr) while True: data =sock.recv(BUFSIZE).decode() print('date=',data) if not data: break sock.send(('[%s] %s' %(ctime(),data)).encode()) sock.close()
客戶端
#coding=utf-8 #創建TCP客戶端 import socket HOST = '127.0.0.1' PORT = 8080 BUFSIZE = 1024 ADDR=(HOST,PORT) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) while True: data = input('> ') if not data: break sock.send(data.encode()) data = sock.recv(BUFSIZE).decode() if not data: break print(data) sock.close()
執行結果顯示:
首先執行服務器端,結果如圖1:
緊接著執行客戶端,如圖2
需要註意的是:服務器端和客戶端需要在兩個IDLE Shell中打開,否則客戶機一啟動,服務器程序就會中止執行,而客戶端又連不上服務器,從而報錯,如圖3
我們在圖2中輸入一些需要傳輸的信息,然後回車,在服務端可以看到收到瞭相關信息,如圖4(客戶端發送信息),圖5(服務器端接收信息)
源代碼解析
我們從服務器端開始看起,先上一部分代碼:
import socket import time from time import ctime
這三句是導入瞭三個模塊,分別是socket 模塊、time模塊和ctime模塊。
1)socket 模塊當中提供瞭與socket 套接字相關的各項功能,後面用到瞭很多,這裡先介紹一個,其他一會再介紹:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
功能:創建套接字,並把創建好的套接字賦給一個變量sock,下面程序中與套接字相關的操作都由sock來完成。
格式:socket.socket([family[, type[, proto]]])
參數:
family: 套接字傢族,可以使 AF_UNIX 或者 AF_INET。AF_INET,是指面向網絡的,因特網;AF_UNIX,基於文件的;在本例中,我們使用AF_INET,利用因特網來進行通信。
type: 套接字類型,可以根據是面向連接的還是非連接分為 SOCK_STREAM 或 SOCK_DGRAM。
SOCK_STREAM:對應著TCP,提供瞭一個面向連接、可靠的數據傳輸服務,數據無差錯、無重復的發送且按發送順序接收。內設置流量控制,避免數據流淹沒慢的接收方。數據被看作是字節流,無長度限制。
SOCK_DGRAM:對應著UDP,提供無連接服務。數據包以獨立數據包的形式被發送,不提供無差錯保證,數據可能丟失或重復,順序發送,可能亂序接收。
本例中選TCP協議。
protocol: 一般不填默認為 0。
2)time模塊,完成python中與時間相關的計算,例如time.sleep(5)延時5秒,time time() 返回當前時間的時間戳等等。
下面的ctime也是其中一個功能,函數把一個時間戳(按秒計算的浮點數)轉化為time.asctime()的形式,可以便於我們觀察。轉換以後的格式如下:
print “time.ctime() : %s” % time.ctime()
結果:time.ctime() : Tue Feb 17 10:00:18 2013
在我們的例子中,圖4的圈2所表示的就是轉換後的時間。
HOST = '127.0.0.1' PORT = 8080 BUFSIZE=1024 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((HOST, PORT)) sock.listen(5) addr=(HOST,PORT)
看完頭部之後,我們來看第二部分。
前三句定義瞭三個變量:HOST、PORT、BUFSIZE,這三個變量分別是服務器的IP地址,服務器的端口,接收的最大數據量。
第四句sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 定義瞭socket 套接字。
第五句sock.bind((HOST, PORT)),將IP地址和端口綁定給定義的套接字sock。
第六句sock.listen(5),開始 TCP 監聽。中間的5表示在拒絕連接之前,操作系統可以掛起的最大連接數量。該值至少為 1,大部分應用程序設為 5 就可以瞭。
第七句addr=(HOST,PORT),定義瞭一個變量addr,並且將地址以元組的形式賦值給addr。
while True: print('waiting for connection...') sock,addr =sock.accept() print('...connected from:',addr) while True: data =sock.recv(BUFSIZE).decode() print('date=',data) if not data: break sock.send(('[%s] %s' %(ctime(),data)).encode()) sock.close() sock.close()
這是服務器代碼的最後一部分,也是通信的主體,首先進入一個while True:的永真循環,進入之後執行print(‘waiting for connection…’),這就是圖1上藍色字所表示的一部分。
第三行執行sock,addr =sock.accept(),sock.accept()是被動接受TCP客戶端連接,(阻塞式)等待連接的到來,當客戶機啟動提交請求後,服務器接受請求,並將客戶端的IP地址等信息存入變量addr中。
第四行執行print(‘…connected from:’,addr),所以輸入字符串…connected from:以及客戶端傳來的IP地址和端口。
以上服務器和客戶端的通信就連接起來瞭。
下面開始傳送數據,又進入一個永真循環,代碼:
while True: data =sock.recv(BUFSIZE).decode() print('date=',data) if not data: break sock.send(('[%s] %s' %(ctime(),data)).encode()) sock.close()
第二行:data =sock.recv(BUFSIZE).decode()。
sock.recv()表示接收 TCP 數據,數據以字符串形式返回,BUFSIZE指定要接收的最大數據量。
decode() 將其他編碼的字符串解碼成unicode格式。
這裡要說明一下,上圖:
字符串在python內部是用unicode編碼來表示,而在硬盤是utf-8格式。所以在存儲和使用時要進行格式轉換,轉換的方式:
decode 將其他編碼的字符串(例如utf-8)解碼成unicode格式。
encode 將unicode編碼成另一種編碼格式(例如utf-8)。
當然decode和encode 不止可以轉換utf-8類型,轉換的類型可以通過 encoding 來指定,不過我們常用的就是這個。
總結一下,data =sock.recv(BUFSIZE).decode()執行結束就表示把客戶端的數據接收過來存放到瞭data這個變量中。
下面進行第三行print(‘date=’,data),打印數據,結果就是圖5中的圈3所表示的。
第四行及第五行: 如果沒有接收到數據,則跳出循環,繼續監聽。
if not data:
break
第六行 sock.send((‘[%s] %s’ %(ctime(),data)).encode()),向客戶端發送轉換格式(encode)後的數據。
數據包括兩部分,第一部分是ctime(),表示以字符串形式表示的時間,data表示變量中存的信息.前面還有一部分'[%s] %s’中的%s格式化字符串,形成需要的輸出格式。
最後一句sock.close(),關閉套接字。
這樣服務器端就完成瞭。我們再來看客戶端。
import socket HOST = '127.0.0.1' PORT = 8080 BUFSIZE = 1024 ADDR=(HOST,PORT) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT))
這部隻解釋幾句,HOST = ‘127.0.0.1′ ,PORT = 8080,這兩句是服務器端的IP地址和端口號。
sock.connect((HOST, PORT)) 這一句是利用創建好的socket套接字主動初始化TCP服務器連接,就是向服務器提出申請,服務器端用sock.accept()接受請求。
這一句執行完之後,通信就建立起來瞭,在服務器端會執行print(‘…connected from:’,addr),結果如圖5圈2所示。
while True: data = input('> ') if not data: break sock.send(data.encode()) data = sock.recv(BUFSIZE).decode() if not data: break print(data) sock.close()
接下來進入永真循環,先是input函數,輸出> 後等待輸入,如圖2所示。例如輸入hi,server,如圖4的圈1,然後後兩句是
if not data:
break
如果沒有輸入,則跳出循環。
第五行sock.send(data.encode()),將輸入的數據轉換格式後將數據發送給服務器端,這時把hi,server發送給服務器端,服務器用data =sock.recv(BUFSIZE).decode()來接收,同時用print(‘date=’,data)打印出來,結果如5的圈3所示。
這時,服務器會繼續執行sock.send((‘[%s] %s’ %(ctime(),data)).encode()),把當前的時間和數據發送給客戶端。
而在客戶端,執行data = sock.recv(BUFSIZ).decode(),所以客戶端會接收到相應的數據,並且打印出來,結果如圖4的圈2所示。
以上就是Socket套接字的TCP通信。
到此這篇關於python基礎之Socket套接字詳解的文章就介紹到這瞭,更多相關python Socket詳解內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- None Found