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:

Tags: