標籤:包含 網路編程 ip地址 自己的 系統 開啟 發送 檔案寫入 完整
Python3網路編程
‘‘‘無論是str2bytes或者是bytes2str其編碼方式都是utf-8str( ,encoding=‘utf-8‘)bytes( ,encoding=‘utf-8‘)而在使用.encode(‘utf-8‘)時,雖然type類型是byte,但常常報錯‘‘‘
Socket又稱"通訊端",應用程式通常通過"通訊端"向網路發出請求或者應答網路請求,使主機間或者一台電腦上的進程間可以通訊。
socket起源於UNIX,在Unix一切皆檔案哲學的思想下,socket是一種"開啟—讀/寫—關閉"模式的實現,伺服器和用戶端各自維護一個"檔案",在建立串連開啟後,可以向自己檔案寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉檔案。socket的英文原義是“插槽”或“插座”,就像我們家裡有線電話一樣,如果沒有網線的那個插口,電話是無法通訊的。Socket是實現TCP,UDP協議的介面,便於使用TCP,UDP。
# 流程描述:## 1 伺服器根據地址類型(ipv4,ipv6)、socket類型、協議建立socket## 2 伺服器為socket綁定ip地址和連接埠號碼## 3 伺服器socket監聽連接埠號碼請求,隨時準備接收用戶端發來的串連,這時候伺服器的socket並沒有被開啟## 4 用戶端建立socket## 5 用戶端開啟socket,根據伺服器ip地址和連接埠號碼試圖串連伺服器socket## 6 伺服器socket接收到用戶端socket請求,被動開啟,開始接收用戶端請求,直到用戶端返回串連資訊。這時候socket進入阻塞狀態,# 所謂阻塞即accept()方法一直等到用戶端返回串連資訊後才返回,開始接收下一個用戶端串連請求## 7 用戶端串連成功,向伺服器發送串連狀態資訊## 8 伺服器accept方法返回,串連成功## 9 用戶端向socket寫入資訊(或服務端向socket寫入資訊)## 10 伺服器讀取資訊(用戶端讀取資訊)## 11 用戶端關閉## 12 伺服器端關閉
Socket 對象(內建)方法伺服器端
s.bind() # 綁定地址(host,port)到通訊端, 在AF_INET下,以元組(host,port)的形式表示地址。s.listen() # 開始TCP監聽。backlog指定在拒絕串連之前,作業系統可以掛起的最大串連數量。該值至少為1,大部分應用程式設為5就可以了。s.accept() # 被動接受TCP用戶端串連,(阻塞式)等待串連的到來
用戶端
s.connect() # 主動初始化TCP伺服器串連,。一般address的格式為元組(hostname,port),如果串連出錯,返回socket.error錯誤。s.connect_ex() # connect()函數的擴充版本,出錯時返回出錯碼,而不是拋出異常
公用用途的函數
s.recv() # 接收TCP資料,資料以字串形式返回,bufsize指定要接收的最大資料量。flag提供有關訊息的其他資訊,通常可以忽略。s.send() # 發送TCP資料,將string中的資料發送到串連的通訊端。傳回值是要發送的位元組數量,該數量可能小於string的位元組大小。s.sendall() # 完整發送TCP資料,完整發送TCP資料。將string中的資料發送到串連的通訊端,但在返回之前會嘗試發送所有資料。成功返回None,失敗則拋出異常。s.close()# 關閉通訊端 s.recvform() # 接收UDP資料,與recv()類似,但傳回值是(data,address)。其中data是包含接收資料的字串,address是發送資料的通訊端地址。s.sendto() # 發送UDP資料,將資料發送到通訊端,address是形式為(ipaddr,port)的元組,指定遠程地址。傳回值是發送的位元組數。s.getpeername() # 返回串連通訊端的遠程地址。傳回值通常是元組(ipaddr,port)。s.getsockname() # 返回通訊端自己的地址。通常是一個元組(ipaddr,port)s.setsockopt(level,optname,value) # 設定給定通訊端選項的值。s.getsockopt(level,optname[.buflen]) # 返回通訊端選項的值。s.settimeout(timeout) # 設定通訊端操作的逾時期,timeout是一個浮點數,單位是秒。值為None表示沒有逾時期。一般,逾時期應該在剛建立通訊端時設定,因為它們可能用於串連的操作(如connect())s.gettimeout() # 返回當前逾時期的值,單位是秒,如果沒有設定逾時期,則返回None。s.fileno() # 返回通訊端的檔案描述符。s.setblocking(flag) # 如果flag為0,則將通訊端設為非阻塞模式,否則將通訊端設為阻塞模式(預設值)。非阻塞模式下,如果調用recv()沒有發現任何資料,或send()調用無法立即發送資料,那麼將引起socket.error異常。s.makefile() # 建立一個與該通訊端相關連的檔案
簡單一實例服務端我們使用 socket 模組的
socket 函數來建立一個 socket 對象。socket 對象可以通過調用其他函數來設定一個 socket 服務。
現在我們可以通過調用 bind(hostname, port) 函數來指定服務的 port(連接埠)。
接著,我們調用 socket 對象的 accept 方法。該方法等待用戶端的串連,並返回 connection 對象,表示已串連到用戶端。
完整代碼如下:
import socket # 匯入socket模組
sk = socket.socket() # 建立socket對象sk.bind(("127.0.0.1", 8888)) # 綁定連接埠,“127.0.0.1”代表本機地址,8888為設定連結的連接埠地址sk.listen(5) # 設定監聽,最多可有5個用戶端進行排隊conn, addr = sk.accept() # 阻塞狀態,被動等待用戶端的串連print(conn) # conn可以理解用戶端的socket對象# <socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=(‘127.0.0.1‘, 9005), raddr=(‘127.0.0.1‘, 36694)>print(addr) # addr為用戶端的連接埠地址# (‘127.0.0.1‘, 40966)accept_data = conn.recv(1024) # conn.recv()接收用戶端的內容,接收到的是bytes類型資料,accept_data2 = str(accept_data, encoding="utf8") # str(data,encoding="utf8")用“utf8”進行解碼print("".join(("接收內容:", accept_data2, " 用戶端口:", str(addr[1]))))send_data = input("輸入發送內容:")conn.sendall(bytes(send_data, encoding="utf8")) # 發送內容必須為bytes類型資料,bytes(data, encoding="utf8")用“utf8”格式進行編碼conn.close()
用戶端接下來我們寫一個簡單的用戶端執行個體串連到以上建立的服務。連接埠號碼為 8888。
socket.connect(hosname, port ) 方法開啟一個 TCP 串連到主機為 “127.0.0.1” 連接埠為 port 的服務商。串連後我們就可以從服務端後期資料,記住,操作完成後需要關閉串連。
完整代碼如下:
import socketsk = socket.socket()sk.connect(("127.0.0.1", 8888)) # 主動初始化與伺服器端的串連send_data = input("輸入發送內容:")sk.sendall(bytes(send_data, encoding="utf8"))accept_data = sk.recv(1024)print(str(accept_data, encoding="utf8"))sk.close()服務端
import socketsk = socket.socket()sk.bind(("127.0.0.1", 9008))sk.listen(5)while True: conn, addr = sk.accept() while True: accept_data = str(conn.recv(1024), encoding="utf8") print("".join(["接收內容:", accept_data, " 用戶端口:", str(addr[1])])) if accept_data == "byebye": # 如果接收到“byebye”則跳出迴圈結束和第一個用戶端的通訊,開始與下一個用戶端進行通訊 break send_data = input("輸入發送內p容:") conn.sendall(bytes(send_data, encoding="utf8")) conn.close() # 跳出迴圈時結束通訊用戶端
import socketsk = socket.socket()sk.connect(("127.0.0.1", 9008)) # 主動初始化與伺服器端的串連while True: send_data = input("輸入發送內容:") sk.sendall(bytes(send_data, encoding="utf8")) if send_data == "byebye": break accept_data = str(sk.recv(1024), encoding="utf8") print("".join(("接收內容:", accept_data)))sk.close()以上簡單一實例中,用戶端必須排隊與服務端進行通訊,只有當前一個客戶斷與服務端通訊完畢後才能與服務斷進行通訊,那麼有沒有方法能讓多個用戶端同時與服務端進行通訊呢?那麼就要用到socketserver模組了:
簡單並發執行個體服務端
import socketserver # 匯入socketserver模組class MyServer(socketserver.BaseRequestHandler): # 建立一個類,繼承自socketserver模組下的BaseRequestHandler類 def handle(self): # 要想實現並發效果必須重寫父類中的handler方法,在此方法中實現服務端的邏輯代碼(不用再寫串連準備,包括bind()、listen()、accept()方法) while 1: conn = self.request addr = self.client_address # 上面兩行代碼,等於 conn,addr = socket.accept(),只不過在socketserver模組中已經替我們封裝好了,還替我們封裝了包括bind()、listen()、accept()方法 while 1: accept_data = str(conn.recv(1024), encoding="utf8") print(accept_data) if accept_data == "byebye": break send_data = bytes(input(">>>>>"), encoding="utf8") conn.sendall(send_data) conn.close()if __name__ == ‘__main__‘: sever = socketserver.ThreadingTCPServer(("127.0.0.1", 8888), MyServer) # 傳入 連接埠地址 和 我們建立的繼承自socketserver模組下的BaseRequestHandler類 執行個體化對象 sever.serve_forever() # 通過調用對象的serve_forever()方法來啟用服務端用戶端
import socketsk = socket.socket()sk.connect(("127.0.0.1", 8888)) # 主動初始化與伺服器端的串連while True: send_data = input("輸入發送內容:") sk.sendall(bytes(send_data, encoding="utf8")) if send_data == "byebye": break accept_data = str(sk.recv(1024), encoding="utf8") print("".join(("接收內容:", accept_data)))sk.close()
『Python』socket網路編程