Python進階【第一篇】socket,python進階socket
1.socket模組
要使用socket.socket()函數來建立通訊端。其文法如下:
socket.socket(socket_family,socket_type,protocol=0)
socket_family可以是如下參數:
socket.AF_INET IPv4(預設)
socket.AF_INET6 IPv6
socket.AF_UNIX 只能夠用於單一的Unix系統處理序間通訊
socket_type可以是如下參數:
socket.SOCK_STREAM 流式socket , for TCP (預設)
socket.SOCK_DGRAM 資料報式socket , for UDP
socket.SOCK_RAW 原始通訊端,普通的通訊端無法處理ICMP、IGMP等網路報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始通訊端,可以通過IP_HDRINCL通訊端選項由使用者構造IP頭。
socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付資料報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在需要執行某些特殊操作時使用,如發送ICMP報文。SOCK_RAM通常僅限於進階使用者或管理員啟動並執行程式使用。
socket.SOCK_SEQPACKET 可靠的連續資料包服務
protocol參數:
0 (預設)與特定的地址家族相關的協議,如果是 0 ,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議
2.通訊端對象內建方法
伺服器端通訊端函數
s.bind() 綁定地址(ip地址,連接埠)到通訊端,參數必須是元組的格式例如:s.bind(('127.0.0.1',8009))
s.listen(5) 開始監聽,5為最大掛起的串連數
s.accept() 被動接受用戶端串連,阻塞,等待串連
用戶端通訊端函數
s.connect() 串連伺服器端,參數必須是元組格式例如:s.connect(('127,0.0.1',8009))
公用用途的通訊端函數
s.recv(1024) 接收TCP資料,1024為一次資料接收的大小
s.send(bytes) 發送TCP資料,python3發送資料的格式必須為bytes格式
s.sendall() 完整發送資料,內部迴圈調用send
s.close() 關閉通訊端
執行個體1.簡單實現socket程式
server端
#!/usr/bin/env python# _*_ coding:utf-8 _*_import socketimport timeIP_PORT = ('127.0.0.1',8009)BUF_SIZE = 1024tcp_server = socket.socket()tcp_server.bind(IP_PORT)tcp_server.listen(5)while True: print("waiting for connection...") conn,addr = tcp_server.accept() print("...connected from:",addr) while True: data = tcp_server.recv(BUF_SIZE) if not data:break tcp_server.send('[%s] %s'%(time.ctime(),data))tcp_server.close()
以上代碼解釋:
1~4行
第一行是Unix的啟動資訊行,隨後匯入time模組和socket模組
5~10行
IP_PORT為全域變數聲明了IP地址和連接埠,表示bind()函數綁定在此地址上,把緩衝區的大小設定為1K,listen()函數表示最多允許多少個串連同時進來,後來的就會被拒絕掉
11~到最後一行
在進入伺服器的迴圈後,被動等待串連的到來。當有串連時,進入對話迴圈,等待用戶端發送資料。如果訊息為空白,表示用戶端已經退出,就跳出迴圈等待下一個串連到來。得到用戶端訊息後,在訊息前面加一個時間戳記然後返回。最後一行不會執行,因為迴圈不會退出所以服務端也不會執行close()。只是提醒不要忘記調用close()函數。
client端
#!/usr/bin/env python# _*_ coding:utf-8 _*_import socketHOST = '127.0.0.1'PORT = 8009BUF_SIZE = 1024ADDR = (HOST,PORT)client = socket.socket()client.connect(ADDR)while True: data = input(">>> ") if not data:break client.send(bytes(data,encoding='utf-8')) recv_data = client.recv(BUF_SIZE) if not recv_data:break print(recv_data.decode()) client.close()
5~11行
HOST和PORT變數表示伺服器的IP地址與連接埠號碼。由於示範是在同一台伺服器所以IP地址都是127.0.0.1,如果運行在其他伺服器上要做相應的修改。連接埠號碼要與伺服器端完全相同否則無法通訊。緩衝區大小還是1K。
用戶端通訊端在10行建立然後就去串連伺服器端
13~21行
用戶端也無限迴圈,用戶端的迴圈在以下兩個條件的任意一個發生後就退出:1.使用者輸入為空白的情況或者伺服器端響應的訊息為空白。否則用戶端會把使用者輸入的字串發送給伺服器進行處理,然後接收顯示伺服器返回來的帶有時間戳記的字串。
運行用戶端程式與服務端程式
以下是用戶端的輸入與輸出
[root@node6 部落格樣本]# python3 tclient.py >>> hello[Thu Sep 15 22:29:12 2016] b'hello'>>> nihao[Thu Sep 15 22:29:32 2016] b'nihao'
以下是服務端輸出
[root@node6 部落格樣本]# python3 tserver.py waiting for connection......connected from: ('127.0.0.1', 55378) 3.socketserver模組
socketserver是標準庫中的一個進階別的模組。用於簡化實現網路用戶端與伺服器所需要的大量樣板代碼。模組中已經實現了一些可以使用的類。
執行個體1:使用socketserver實現與上面socket()執行個體一樣的功能
服務端程式碼
#!/usr/bin/env python# _*_ coding:utf-8 _*_import socketserverimport timeHOST = '127.0.0.1'PORT = 8009ADDR = (HOST,PORT)BUF_SIZE = 1024class Myserver(socketserver.BaseRequestHandler): def handle(self): while True: print("...connected from:",self.client_address) data = self.request.recv(BUF_SIZE) if not data:break self.request.send(bytes("%s %s"%(time.ctime(),data)))server = socketserver.ThreadingTCPServer(ADDR,Myserver)print("waiting for connection...")server.serve_forever()
11~17行
主要的工作在這裡。從socketserver的BaseRequestHandler類中派生出一個子類,並重寫handle()函數。
在有用戶端發進來的訊息的時候,handle()函數就會被調用。
19~21行
代碼的最後一部分用給定的IP地址和連接埠加上自訂處理請求的類(Myserver)。然後進入等待用戶端請求與處理用戶端請求的無限迴圈中。
用戶端程式代碼
import socketHOST = '127.0.0.1'PORT = 8009ADDR = (HOST,PORT)BUF_SIZE = 1024client = socket.socket()client.connect(ADDR)while True: data = input(">>> ") if not data:continue client.send(bytes(data,encoding='utf-8')) recv_data = client.recv(BUF_SIZE) if not recv_data:break print(recv_data.decode())client.close()
執行服務端和用戶端代碼
下面是用戶端輸出
[root@node6 blog樣本2]# python3 tsocketclient.py >>> helloThu Sep 15 23:53:31 2016 b'hello'>>> nihaoThu Sep 15 23:53:49 2016 b'nihao'>>> heheThu Sep 15 23:53:53 2016 b'hehe'
下面是服務端輸出
[root@node6 blog樣本2]# python3 tsocketserver.py waiting for connection......connected from: ('127.0.0.1', 55385)...connected from: ('127.0.0.1', 55385)...connected from: ('127.0.0.1', 55385)...connected from: ('127.0.0.1', 55385)