Python网络编程学习_Day9
一、socketserver实现多并发
socket只能实现单进程通讯,要实现多进程同时和服务端通讯就要使用socketserver。
代码如下:
1 import socket 2 client = socket.socket() 3 client.connect(("localhost",9000)) 4 while True: 5 choice = input(">>>:") 6 if len(choice) == 0:continue 7 client.send(choice.encode()) 8 recv = client.recv(1024) 9 print("recved:",recv.decode())
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Liumj 4 import socketserver 5 class MyTCPHandler(socketserver.BaseRequestHandler): 6 def handle(self): 7 while True: 8 self.data = self.request.recv(1024).strip() 9 print(self.client_address[0]) 10 print(self.data) 11 self.request.sendall(self.data.upper()) 12 if __name__ =="__main__": 13 HOST,PORT = "localhost",9000 14 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) 15 server.serve_forever()
二、FTP程序开发
1.服务端代码
1 import socketserver 2 import configparser 3 from conf import settings 4 import os 5 import hashlib 6 import time 7 t = time.strftime("%H_%M_%S") 8 9 STATUS_CODE = { 10 250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}", 11 251 : "Invalid cmd ", 12 252 : "Invalid auth data", 13 253 : "Wrong username or password", 14 254 : "Passed authentication", 15 255 : "Filename doesn't provided", 16 256 : "File doesn't exist on server", 17 257 : "ready to send file", 18 258 : "md5 verification", 19 } 20 import json 21 class FTPHandler(socketserver.BaseRequestHandler): 22 def handle(self): 23 while True: 24 self.data = self.request.recv(1024).strip() 25 print(self.client_address[0]) 26 print(self.data) 27 if not self.data: 28 print("client closed...") 29 break 30 data = json.loads(self.data.decode()) 31 if data.get('action') is not None: 32 print("---->",hasattr(self,"_auth")) 33 if hasattr(self,"_%s"%data.get('action')): 34 func = getattr(self,"_%s"% data.get('action')) 35 func(data) 36 else: 37 print("invalid cmd") 38 self.send_response(251) 39 else: 40 print("invalid cmd format") 41 self.send_response(250) 42 43 def send_response(self,status_code,data=None): 44 '''向客户端返回数据''' 45 response = {'status_code':status_code,'status_msg':STATUS_CODE[status_code]} 46 if data: 47 response.update( data ) 48 self.request.send(json.dumps(response).encode()) 49 50 def _auth(self,*args,**kwargs): 51 data = args[0] 52 if data.get("username") is None or data.get("password") is None: 53 self.send_response(252) 54 55 user =self.authenticate(data.get("username"),data.get("password")) 56 if user is None: 57 self.send_response(253) 58 else: 59 print("passed authentication",user) 60 self.user = user 61 self.send_response(254) 62 def authenticate(self,username,password): 63 '''验证用户合法性,合法就返回用户数据''' 64 65 config = configparser.ConfigParser() 66 config.read(settings.ACCOUNT_FILE) 67 if username in config.sections(): 68 _password = config[username]["Password"] 69 if _password == password: 70 print("pass auth..",username) 71 config[username]["Username"] = username 72 return config[username] 73 74 def _put(self,*args,**kwargs): 75 "client send file to server" 76 data = args[0] 77 # if data.get('filename') is None: 78 # self.send_response(255) 79 user_home_dir = "%s/%s" % (settings.USER_HOME, self.user["Username"]) 80 file_abs_path = "%s/%s" % (user_home_dir, data.get('filename')) 81 print("file abs path", file_abs_path) 82 print("server.....") 83 self.send_response(257) 84 received_size = 0 85 total_size = int(self.request.recv(1024)) 86 file_obj = open(file_abs_path+t, "wb") 87 #print("zhaodao.....") 88 while received_size < total_size: 89 data = self.request.recv(4096) 90 received_size +=len(data) 91 file_obj.write(data) 92 else: 93 print("---recv done...") 94 file_obj.close() 95 96 def _get(self,*args,**kwargs): 97 data = args[0] 98 if data.get('filename') is None: 99 self.send_response(255) 100 user_home_dir = "%s/%s" %(settings.USER_HOME,self.user["Username"]) 101 file_abs_path = "%s/%s" %(user_home_dir,data.get('filename')) 102 print("file abs path",file_abs_path) 103 104 if os.path.isfile(file_abs_path): 105 file_obj = open(file_abs_path,"rb") 106 file_size = os.path.getsize(file_abs_path) 107 self.send_response(257,data={'file_size':file_size}) 108 self.request.recv(1) #等待客户端确认 109 110 if data.get('md5'): 111 md5_obj = hashlib.md5() 112 for line in file_obj: 113 self.request.send(line) 114 md5_obj.update(line) 115 else: 116 file_obj.close() 117 md5_val = md5_obj.hexdigest() 118 self.send_response(258,{'md5':md5_val}) 119 print("send file done....") 120 else: 121 for line in file_obj: 122 self.request.send(line) 123 else: 124 file_obj.close() 125 print("send file done....") 126 else: 127 self.send_response(256) 128 129 def _ls(self,*args,**kwargs): 130 pass 131 132 def _cd(self, *args, **kwargs): 133 pass 134 135 if __name__ == "__main__": 136 HOST, PORT = "localhost", 9000
2.客户端代码
1 import socket 2 import os ,json 3 import optparse 4 import getpass 5 import hashlib 6 import sys 7 8 STATUS_CODE = { 9 250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}", 10 251 : "Invalid cmd ", 11 252 : "Invalid auth data", 12 253 : "Wrong username or password", 13 254 : "Passed authentication", 14 255 : "Filename doesn't provided", 15 } 16 17 class FTPClient(object): 18 def __init__(self): 19 parser = optparse.OptionParser() 20 parser.add_option("-s","--server", dest="server", help="ftp server ip_addr") 21 parser.add_option("-P","--port",type="int", dest="port", help="ftp server port") 22 parser.add_option("-u","--username", dest="username", help="username") 23 parser.add_option("-p","--password", dest="password", help="password") 24 self.options , self.args = parser.parse_args() 25 self.verify_args(self.options,self.args) 26 self.make_connection() 27 28 def make_connection(self): 29 self.sock = socket.socket() 30 self.sock.connect((self.options.server,self.options.port)) 31 32 def verify_args(self, options,args): 33 '''校验参数合法型''' 34 if options.username is not None and options.password is not None: 35 pass 36 elif options.username is None and options.password is None: 37 pass 38 else: 39 #options.username is None or options.password is None: 40 exit("Err: username and password must be provided together..") 41 42 if options.server and options.port: 43 #print(options) 44 if options.port >0 and options.port <65535: 45 return True 46 else: 47 exit("Err:host port must in 0-65535") 48 49 def authenticate(self): 50 '''用户验证''' 51 if self.options.username: 52 print(self.options.username,self.options.password) 53 return self.get_auth_result(self.options.username, self.options.password) 54 else: 55 retry_count = 0 56 while retry_count <3: 57 username = input("username:").strip() 58 password = input("password:").strip() 59 return self.get_auth_result(username,password) 60 61 def get_auth_result(self,user,password): 62 data = {'action':'auth', 63 'username':user, 64 'password':password} 65 66 self.sock.send(json.dumps(data).encode()) 67 response = self.get_response() 68 if response.get('status_code') == 254: 69 print("Passed authentication!") 70 self.user = user 71 return True 72 else: 73 print(response.get("status_msg")) 74 75 def get_response(self): 76 '''得到服务器端回复结果''' 77 data = self.sock.recv(1024) 78 print("server res", data) 79 data = json.loads(data.decode()) 80 return data 81 82 83 84 def interactive(self): 85 if self.authenticate(): 86 print("---start interactive iwth u...") 87 while True: 88 choice = input("[%s]:"%self.user).strip() 89 if len(choice) == 0:continue 90 cmd_list = choice.split() 91 if hasattr(self,"_%s"%cmd_list[0]): 92 func = getattr(self,"_%s"%cmd_list[0]) 93 func(cmd_list) 94 else: 95 print("Invalid cmd.") 96 97 def __md5_required(self,cmd_list): 98 '''检测命令是否需要进行MD5验证''' 99 if '--md5' in cmd_list: 100 return True 101 def show_progress(self,total): 102 received_size = 0 103 current_percent = 0 104 while received_size < total: 105 if int((received_size / total) * 100 ) > current_percent : 106 print("#",end="",flush=True) 107 current_percent = int((received_size / total) * 100 ) 108 new_size = yield 109 received_size += new_size 110 def _get(self,cmd_list): 111 print("get--",cmd_list) 112 if len(cmd_list) == 1: 113 print("no filename follows...") 114 return 115 data_header = { 116 'action':'get', 117 'filename':cmd_list[1] 118 } 119 if self.__md5_required(cmd_list): 120 data_header['md5'] = True 121 122 self.sock.send(json.dumps(data_header).encode()) 123 response = self.get_response() 124 print(response) 125 if response["status_code"] ==257:#ready to receive 126 self.sock.send(b'1')#send confirmation to server 127 base_filename = cmd_list[1].split('/')[-1] 128 received_size = 0 129 file_obj = open(base_filename,"wb") 130 if self.__md5_required(cmd_list): 131 md5_obj = hashlib.md5() 132 progress = self.show_progress(response['file_size']) #generator 133 progress.__next__() 134 while received_size < response['file_size']: 135 data = self.sock.recv(4096) 136 received_size += len(data) 137 try: 138 progress.send(len(data)) 139 except StopIteration as e: 140 print("100%") 141 file_obj.write(data) 142 md5_obj.update(data) 143 else: 144 print("----->file rece done----") 145 file_obj.close() 146 md5_val = md5_obj.hexdigest() 147 md5_from_server = self.get_response() 148 if md5_from_server['status_code'] == 258: 149 if md5_from_server['md5'] == md5_val: 150 print("%s 文件一致性校验成功!" % base_filename) 151 #print(md5_val,md5_from_server) 152 153 else: 154 progress = self.show_progress(response['file_size']) #generator 155 progress.__next__() 156 157 while received_size < response['file_size']: 158 data = self.sock.recv(4096) 159 received_size += len(data) 160 file_obj.write(data) 161 try: 162 progress.send(len(data)) 163 except StopIteration as e: 164 print("100%") 165 166 else: 167 print("----->file recv done----") 168 file_obj.close() 169 def _put(self,cmd_list): 170 print("put----",cmd_list) 171 if len(cmd_list) == 1: 172 print("no filename follows...") 173 return 174 data_header = { 175 'action':'put', 176 'filename':cmd_list[1] 177 } 178 self.sock.send(json.dumps(data_header).encode()) 179 #response = self.get_response() 180 #print(response) 181 print("client......") 182 file_obj = open(cmd_list[1],"rb") 183 file_size = os.stat(cmd_list[1]).st_size 184 print(file_size) 185 self.sock.send(str(file_size).encode()) 186 self.sock.recv(1024) #等待服务端确认 187 progress = self.show_progress(file_size) # generator 188 progress.__next__() 189 for i in file_obj: 190 self.sock.send(i) 191 else: 192 try: 193 progress.send(int(file_size)) 194 except StopIteration as e: 195 print("100%") 196 file_obj.close() 197 print("send done...") 198 if __name__ == "__main__": 199 ftp = FTPClient() 200 ftp.interactive() #交互