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.0python.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.0python.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()