Python的socket編程,有興趣了解一下?
- 2019 年 10 月 6 日
- 筆記
Socket介紹
Socket又稱"套接字",應用程式通常通過"套接字"向網路發出請求或者應答網路請求,使主機間或者一台電腦上的進程間可以通訊。
socket起源於UNIX,在Unix一切皆文件哲學的思想下,socket是一種"打開—讀/寫—關閉"模式的實現,伺服器和客戶端各自維護一個"文件",在建立連接打開後,可以向自己文件寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉文件。socket的英文原義是「插槽」或「插座」,就像我們家裡座機一樣,如果沒有網線的那個插口,電話是無法通訊的。Socket是實現TCP,UDP協議的介面,便於使用TCP,UDP。
Socket流程介紹
socket的通訊流程我們在這裡簡化成10個step:
step1:創建伺服器socket和客戶端socket(兩個py文件)
step2:伺服器綁定socket的ip地址和埠號
step3:伺服器監聽埠號的請求
step4:客戶端打開socket,通過step2提供的IP和埠號去和伺服器完成連接
step5:伺服器此時接收客戶端socket請求,等客戶端返回連接資訊(此時進入阻塞狀態)
step6:客戶端連接成功,向伺服器發送連接成功的狀態資訊
step7:客戶端向socket寫入資訊(or服務端寫入資訊)
step8:服務端讀取socket資訊(or客戶端讀取資訊)
step9:關閉客戶端
step10:關閉伺服器

之後就是通過程式碼來實現socket通訊了:
曬程式碼了
伺服器端:
import socket # 導入socket模組
sk = socket.socket() # 創建socket對象
sk.bind(("127.0.0.1", 1234))
# 綁定埠,「127.0.0.1」代表本機地址,1234為設置鏈接的埠地址
sk.listen(5) # 設置監聽,最多可有5個客戶端進行排隊
conn, addr = sk.accept() # 阻塞狀態,被動等待客戶端的連接
accept_data = conn.recv(1024)
# conn.recv()接收客戶端的內容,接收到的是bytes類型數據,
accept_data2 = str(accept_data, encoding="utf-8")
# str(data,encoding="utf8")用「utf8」進行解碼
print("".join(("接收內容:", accept_data2, " 客戶埠:", str(addr[1]))))
send_data = input("輸入發送內容:")#輸入發送資訊
conn.sendall(bytes(send_data, encoding="utf-8"))
# 發送內容必須為bytes類型數據,bytes(data, encoding="utf8")用「utf8」格式進行編碼
conn.close()#關閉連接
客戶端:
import socket # 導入socket模組
sk = socket.socket() # 創建socket對象
sk.connect(("127.0.0.1", 1234)) # 初始化與伺服器端的連接
send_data = input("輸入發送內容:") #輸入發送資訊
sk.sendall(bytes(send_data, encoding="utf-8")) # 發送內容必須為bytes類型數據,bytes(data, encoding="utf8")用「utf8」格式進行編碼
accept_data = sk.recv(1024) #接收服務端的內容,接收到的是bytes類型數據,
print(str(accept_data, encoding="utf-8"))
sk.close()#關閉連接
以上我們就完成了簡單的單次通訊了
這邊我們介紹一下Socket對象的一些方法:
服務端
sk.bind()
# 綁定地址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示地址。
sk.listen()
# 開始TCP監聽。backlog指定在拒絕連接之前,作業系統可以掛起的最大連接數量。該值至少為1,大部分應用程式設為5就可以了。
sk.accept()
# 被動接受TCP客戶端連接,(阻塞式)等待連接的到來
客戶端
s.connect()
# 主動初始化TCP伺服器連接,。一般address的格式為元組(hostname,port),如果連接出錯,返回socket.error錯誤。
s.connect_ex()
# connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常
公用函數
sk.recv()
# 接收TCP數據,數據以字元串形式返回,bufsize指定要接收的最大數據量。flag提供有關消息的其他資訊,通常可以忽略。
sk.send()
# 發送TCP數據,將string中的數據發送到連接的套接字。返回值是要發送的位元組數量,該數量可能小於string的位元組大小。
sk.sendall()
# 完整發送TCP數據,完整發送TCP數據。將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常。
sk.recvform()
# 接收UDP數據,與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字元串,address是發送數據的套接字地址。
sk.sendto()
# 發送UDP數據,將數據發送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發送的位元組數。
sk.getpeername()
# 返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)。
sk.getsockname()
# 返回套接字自己的地址。通常是一個元組(ipaddr,port)
sk.setsockopt(level,optname,value)
# 設置給定套接字選項的值。
sk.getsockopt(level,optname[.buflen])
# 返回套接字選項的值。
sk.settimeout(timeout)
# 設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因為它們可能用於連接的操作(如connect())
sk.gettimeout()
# 返回當前超時期的值,單位是秒,如果沒有設置超時期,則返回None。
sk.fileno()
# 返回套接字的文件描述符。
sk.setblocking(flag)
# 如果flag為0,則將套接字設為非阻塞模式,否則將套接字設為阻塞模式(默認值)。非阻塞模式下,如果調用recv()沒有發現任何數據,或send()調用無法立即發送數據,那麼將引起socket.error異常。
sk.makefile()
# 創建一個與該套接字相關連的文件
sk.close()
# 關閉套接字
下面我們來實現一下,持續通訊:
server:

client:
