socket只能實現同時一個服務和一個客戶端實現交互,socketserver可以實現多個客戶端同時和服務端交互
1.利用Socket編寫簡單的同一個端口容許多次會話的小案例:
服務端:
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author:CarsonLi import socket '''模擬服務端''' server=socket.socket() server.bind(('localhost',6969)) #綁定需要監聽的端口 server.listen(5) #開始監聽 print('開始等待客戶端發起請求') while True: conn,addr=server.accept() #等待客戶端連接,並且返回兩個參數 #conn是客戶端連接過來而在服務器為期生成的一個連接實例, addr為連接的地址 print('服務器為客戶端連接生成的實例:',conn) print('客戶端連接地址:',addr) while True: data=conn.recv(1024) #接收客戶端發來的信息 print(data.decode()) conn.send(data.upper()) #返回個客戶端信息 server.close()
客戶端:
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # Author:CarsonLi import socket '''模擬客戶端''' client=socket.socket() #聲明socket類型,同時創建socket連接對象 client.connect(('localhost',6969)) while True: msg=input('請輸入需要發送的內容>>:').strip() if len(msg)==0: #輸入信息為空時不發送,否則在linux下運行時會出現死循環 continue else: client.send(msg.encode("utf-8")) #發送信息 在python3以后都只能發送byte類型, data=client.recv(1024)#接收到的信息,需要定義大小 print(data.decode()) client.close()
服務端運行結果:
D:\Python3.7.0\python.exe D:/PycharmProjects/OldManS14/day07/socket_server.py 開始等待客戶端發起請求 服務器為客戶端連接生成的實例: <socket.socket fd=436, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6969), raddr=('127.0.0.1', 64403)> 客戶端連接地址: ('127.0.0.1', 64403) 第一次 第二次 第三次 第四次 第五次
客戶端運行結果:
D:\Python3.7.0\python.exe D:/PycharmProjects/OldManS14/day07/socket_client.py 請輸入需要發送的內容>>:第一次 第一次 請輸入需要發送的內容>>:第二次 第二次 請輸入需要發送的內容>>:第三次 第三次 請輸入需要發送的內容>>:第四次 第四次 請輸入需要發送的內容>>:第五次 第五次 請輸入需要發送的內容>>:
2.SocketServer 支持多個客戶端
''' SocketServer 支持多個客戶端 ''' import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): ''' 處理我們的socket,這個類必須繼承socketserver.BaseRequestHandler 並且實現里面的handler函數 ''' def setup(self): print("這里處理請求前的的事情,也可以不寫") pass def handle(self): '''處理客戶端請求''' while self: try: self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0]))#客戶端地址 print(self.data) self.request.send(self.data.upper()) except ConnectionResetError as e: print("客戶端斷開", e) break def finish(self): print("處理請求完成之后的事情,也可以不寫") pass if __name__=="__main__": HOST,PORT = "localhost",6969 # server = socketserver.TCPServer((HOST,PORT),MyTCPHandler #不支持多並發 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) #支持多線程,多並發 # server = socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler) # 支持多進程,多並發,windows不能實現,linux上可以 #server.allow_reuse_address() #解決 在 socketServer程序里面出現 地址已經被占用 server.serve_forever()
3.模擬ftp上傳下載(只實現了里面的上傳功能,其他功能也大同小異,就沒有一一去寫)
import socketserver,os,json '''模擬ftp上傳下載的服務端''' class MyTCPHandler(socketserver.BaseRequestHandler): def setup(self): pass def handle(self): while True: try: self.data = self.request.recv(1024).strip() print("{}".format(self.client_address[0])) msg_dic = json.loads(self.data.decode()) print(msg_dic) if hasattr(self,"server_"+msg_dic.get("action")): func = getattr(self,"server_"+msg_dic.get("action")) func(msg_dic) except ConnectionResetError as e: print(e) break def server_put(self,*args): '''服務端文件上傳操作''' msg_dic = args[0] file_name = msg_dic.get("file_name") #文件名稱 file_size = msg_dic.get("file_size")#文件大小 if os.path.isfile(file_name): files = file_name.split(".") #截取文件名添加new ,例如 file.txt ==> file_new.txt f = open(files[0]+"_new."+files[1],"wb") else: f = open(file_name, "wb") self.request.send(b"200 ok") recv_file_size = 0 while recv_file_size < file_size: recv_data = self.request.recv(1024) f.write(recv_data) recv_file_size += len(recv_data) #大小計算 else: print("file [%s] has uploaded..." % file_name) f.close() def server_get(self,*args): ''' 下載文件功能 ''' pass def server_del(self,*args): ''' 下載刪除功能 ''' pass if __name__ == "__main__": ip,port = "localhost",9999 server = socketserver.ThreadingTCPServer((ip,port),MyTCPHandler) server.serve_forever()
客戶端:
import socket,os,json '''模擬ftp上傳下載的客戶端''' class MyTCPClient(object): def __init__(self): self.client=socket.socket() def help(self): pass def connection(self,ip,port): '''連接服務器''' self.client.connect((ip, port)) def interactive(self): while True: input_str = input(">>:").strip() if len(input_str) == 0: continue action = input_str.split()[0] if hasattr(self,"cmd_"+action): #用反射判斷是否存在 func = getattr(self,"cmd_"+action) func(input_str) else: print(action,"is not exist!") def client_put(self,*args): '''客戶端文件上傳操作''' input_str = args[0] input_split = input_str.split() if os.path.isfile(input_split[1]): # 判斷是否是文件 file_size = os.stat(input_split[1]).st_size msg_dic = { "action":input_split[0], "file_name":input_split[1], "file_size":file_size } self.client.send(json.dumps(msg_dic).encode("utf-8")) #序列化之后編碼 server_respone = self.client.recv(1024) #等待客戶端確認 f = open(input_split[1],"rb") #打開文件 for line in f: self.client.send(line) else: print(input_split[1],"upload success!") f.close() #關閉文件 else: print(input_split[1], "is not exist!") def client_get(self,*args): '''文件下載操作''' pass def client_del(self,*args): '''刪除功能''' pass if __name__ == "__main__": tcp_client = MyTCPClient() tcp_client.connection("localhost",9999) tcp_client.interactive()