socket實現多個連接
前戲很重要~~
在實現多個連接之前,先實現下多次發送和接收數據。
如果要多次接收數據,那么在服務器端的接收和客戶端的發送部分就必須使用循環。
以下代碼在python3.5下運行。
服務器端:
#服務器端 import socket server = socket.socket() server.bind(('localhost',6969))#綁定要監聽的端口 server.listen() #監聽 conn,address = server.accept() #等待接收數據 返回兩個值,一個是對方的標記位,一個是對方的地址 while True: data = conn.recv(1024) #接收數據,誰發數據給我就用誰的標記位接收 print(data) conn.send(data.upper()) #發送數據,要發給誰就用誰的標記位 server.close()
客戶端:
#客戶端 import socket client = socket.socket()#聲明socket類型,同時生成socket連接對象 client.connect(('localhost',6969)) while True: msg = input('>>').strip() client.send(msg.encode("utf-8")) #發送數據 data = client.recv(1024) #接收指定大小的字節 print(data.decode()) # client.close()
直接把用戶輸入的內容發送給服務器。
執行結果:
#=========客戶端======== >>你好 你好 >>中國 中國 >>hello world HELLO WORLD >> Process finished with exit code 1 #========服務器端========= b'\xe4\xbd\xa0\xe5\xa5\xbd' b'\xe4\xb8\xad\xe5\x9b\xbd' b'hello world' Traceback (most recent call last): ... ConnectionResetError: [WinError 10054] 遠程主機強迫關閉了一個現有的連接。 Process finished with exit code 1
可以看到這里已經實現了多少發送和接收的效果,但是如果客戶端斷開連接,服務器端也被迫中斷。
在python2下如果客戶端突然中斷,服務器端並不會直接中斷。
以下實驗在Python2環境下。
單個客戶端通信
服務器端代碼:
#-*-coding:utf-8 -*- import socket server = socket.socket() server.bind(('localhost',6969))#綁定要監聽的端口 server.listen(1) #監聽 最多可以掛起多少個連接 conn,address = server.accept() #等待接收數據 返回兩個值,一個是對方的標記位,一個是對方的地址 while True: data = conn.recv(1024) #接收數據,誰發數據給我就用誰的標記位接收 print('recv:',data) conn.send(data.upper()) #發送數據,要發給誰就用誰的標記位 server.close()
客戶端代碼:
#-*- coding=utf-8 -*- #客戶端 import socket client = socket.socket()#聲明socket類型,同時生成socket連接對象 client.connect(('localhost',6969)) while True: msg = raw_input('>>').strip() client.send(msg.encode("utf-8")) #發送數據 data = client.recv(1024) #接收指定大小的字節 print('recv:',data.decode()) # client.close()
開始通信:
首先客戶端先發送數據:
在看服務器端接收:
發送接收正常。
現在用CTRL+c斷開客戶端之后服務器端的情況。
修改服務器端代碼, 加一個統計,查看下什么時候開始死循環的。
import socket server = socket.socket() server.bind(('localhost',6969))#綁定要監聽的端口 server.listen(1) #監聽 conn,address = server.accept() #等待接收數據 返回兩個值,一個是對方的標記位,一個是對方的地址 count=0 #統計 條件 while True: data = conn.recv(1024) #接收數據,誰發數據給我就用誰的標記位接收 print('recv:',data) conn.send(data.upper()) #發送數據,要發給誰就用誰的標記位 count+=1 if count >10: break server.close()
客戶端發送接收數據結果。
服務器端發送接收數據結果。
因為客戶端斷開,服務器端接收的都是空。
優化服務器端,斷開就退出
#-*-coding:utf-8 -*- import socket server = socket.socket() server.bind(('localhost',6969))#綁定要監聽的端口 server.listen(1) #監聽 conn,address = server.accept() #等待接收數據 返回兩個值,一個是對方的標記位,一個是對方的地址 while True: data = conn.recv(1024) #接收數據,誰發數據給我就用誰的標記位接收 print('recv:',data) if not data: print('客戶端斷開連接...') #客戶端斷開就退出 break conn.send(data.upper()) #發送數據,要發給誰就用誰的標記位 server.close()
客戶端:
服務器端:
客戶端斷開,服務器直接退出。
多個客戶端通信
怎么讓服務器端一直保持接收狀態呢?
想要 一直保持接收狀態就要在客戶端斷開之后,繼續執行server.accept()。
對的。在server.accept()之前在加一個while,當一個客戶端斷開了之后break,跳出最里層的循環的時候,又繼續server.accept()。
#-*-coding:utf-8 -*- import socket server = socket.socket() server.bind(('localhost',6969))#綁定要監聽的端口 server.listen(1) #監聽 while True: conn,address = server.accept() #等待接收數據 返回兩個值,一個是對方的標記位,一個是對方的地址 while True: data = conn.recv(1024) #接收數據,誰發數據給我就用誰的標記位接收 print('recv:',data) if not data: print('客戶端斷開連接...') break conn.send(data.upper()) #發送數據,要發給誰就用誰的標記位 server.close()
修改並啟動服務器端代碼。
客戶端1
客戶端2
服務器端
斷開客戶端1之后:
服務器端
客戶端2
簡單的實現了能多個連接,但是只能同時跟一個客戶端通信的功能。。
模擬SSH
既然可以發數據過來,那么也可以把這個數據做為命令執行。
首先修改服務器端,發送過來的命令執行並把結果返回給客戶端。
服務器端代碼:
#-*-coding:utf-8 -*- import socket import os server = socket.socket() server.bind(('localhost',6969))#綁定要監聽的端口 server.listen(1) #監聽 while True: conn,address = server.accept() #等待接收數據 返回兩個值,一個是對方的標記位,一個是對方的地址 while True: data = conn.recv(1024) #接收數據,誰發數據給我就用誰的標記位接收 print('recv:',data) if not data: print('客戶端斷開連接...') break res = os.popen(data).read() conn.send(res) #發送數據,要發給誰就用誰的標記位 server.close()
客戶端代碼:
#-*- coding=utf-8 -*- #客戶端 import socket client = socket.socket()#聲明socket類型,同時生成socket連接對象 client.connect(('localhost',6969)) while True: msg = raw_input('>>').strip() client.send(msg.encode("utf-8")) #發送數據 data = client.recv(1024) #接收指定大小的字節 print(data) # client.close()
執行客戶端
服務器端
這里是有返回的,如果一條命令的返回數據大於了定義的接收的大小,那么這次客戶端接收的數據就不全,剩余的數據要等到服務器下次發送才能接收過來。比如定義的接收數據大小是1024,那么一次只能接收1024字節的數據。其余的數據都是在緩沖區里面。因為客戶端不知道要接收幾次。所以服務器端應該把本次要發送的數據大小先發過來,客戶端就知道要接收幾次了。