-
Scoket概念:
socket本質上就是在2台網絡互通的電腦之間,架設一個通道,兩台電腦通過這個通道來實現數據的互相傳遞。 我們知道網絡 通信 都 是基於 ip+port 方能定位到目標的具體機器上的具體服務,操作系統有0-65535個端口,每個端口都可以獨立對外提供服務,如果 把一個公司比做一台電腦 ,那公司的總機號碼就相當於ip地址, 每個員工的分機號就相當於端口, 你想找公司某個人,必須 先打電話到總機,然后再轉分機 。 建立一個socket必須至少有2端, 一個服務端,一個客戶端, 服務端被動等待並接收請求,客戶端主動發起請求, 連接建立之后,雙方可以互發數據。(利用IP和端口實現兩個設備的通信)。 -
Socket核心方法:
接收端: import socket socket.TCP/IP listen(ip,port) waiting()#等待數據 recv()#接收數據 send()#再發送數據
發送端: import socket socket.TCP/IP connect(a.ip,a.port)#接受端主機的IP,端口(port:端口號) socket.send(hello)#發送的數據sendall()名義上是一次性發送所有的數據,但是由於系統原因還是有限制的 socket.recv()#接收數據 socket.close()#關閉
-
實例列舉:
服務器端: import socket server=socket.socket()#設置連接 server.bind((“localhost”,8888))#綁定連接(參數是一個元組) server.listen(5)#監聽 conn,addr=server.accept()#等待 data=conn.recv(1024)#接收(是byte類型的,需要轉換(一般編為utf-8)) conn.sendall(data)#一次性發送所有數據(由於系統原因,是發送不了所有的數據的) server.close()
客戶端: import socket client=socket.socket() client=connect((“localhost”,8888))#建立連接,參數是一個元組 data=input().strip()#手工輸入的是unicode類型,但是再傳輸的時候是要編碼的 client.send(data.encode(“utf-8”))#發送數據 data=client.recv(1024)#收到的數據是utf-8編碼的,所以直接輸出是亂碼 client.close()
-
粘包:
當你連續的調用send()時,由於接收時recv()有大小限制,會發生發送的數據量大於接收的數據量,導致接收的數據不是你期待的數據,這個時候就發生了粘包(兩次發送的數據被同一次接收) 為了避免這種錯誤,我們通常會設計反饋,即你發送一次數據,我們會吧發送的數據反饋給發送給你。這樣兩次發送中間夾雜着一次接收,避免了數據在緩沖中導致粘包。 -
一些注意的地方:
- 發送與接收的類型:
我們在Python3中,默認是Unicode,而在發送數據(send)時,函數send()的參數類型是:Byte,所以我們要進行數據的轉換:
str==>bytes | bytes==>str |
a=”qweqwe” =>a的類型為str str==>bytes b=a.encode(“utf-8”) |
b=b”hello word” =>b為bytes類型 bytes==>str s=b.decode(“utf-8”) |
- 數據的校驗:
字符串類型的,我們可以利用hashlib包中的md5算法來檢驗
文件類型的,我們可以對比兩個文件的區別:
diff file1 file2 |
觀察兩個文件是否一致(文件檢測) |
SocketServer:
這個比較方便,它集成了一些東西,很方便的,只是server端改變了一下書寫方式,客戶端不用改變
代碼如下:
#this is server import socketserver class MyTCPHandler(socketserver.BaseRequestHandler):#類名隨意,但是繼承的不能改變 def handle(self):#系統會自動調用這個函數,我們只需要在這個函數中寫我們要實現的方法就可以了 while True: try: self.data=self.request.recv(1024).strip() print("{} wrote".format(self.client_address)) print(self.data) self.request.send(self.data.upper()) except ConnectionResetError as e: print("error: ",e) break if __name__ =="__main__": HOST,PORT="localhost",9999#聲明IP與端口 server=socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)#設置連接 server.serve_forever()#建立連接,然后系統在連接成功以后會自動調用函數handle()
#this is client import socket client=socket.socket() client.connect(("localhost",9999)) while True: cmd=input(">>").strip() if cmd =="": continue client.send(cmd.encode()) data=client.recv(1024) print(data)
附:
socket一個最簡單的通信:
#服務器端: import socket server=socket.socket() server.bind(("localhost",8888)) server.listen() conn,addr=server.accept() count=10 while count: data=conn.recv(1024) print(data.decode("utf-8")) conn.send(data) count-=1 server.close()
#客戶端 import socket client=socket.socket() client.connect(("localhost",8888)) while True: chioce=input(">>").strip() client.sendall(chioce.encode("utf-8")) data=client.recv(1024) if not data: break print(data.decode("utf-8")) client.close()