FTP Server
Import socketimport structfrom concurrent.futures import threadpoolexecutorimport jsonimport hashlibimport Osimport Timefrom Demo Import Common_utilsput_file_dir = R ' C:\x\LuffyFTP\sharefile\server\put ' Get_file_dir = R ' C:\x\LuffyFTP\ Sharefile\server\get ' Ip_port = (' 127.0.0.1 ', 9999) def run_forever (): "" "Start Socket:return:" "Server_so Cket = Socket.socket (socket.af_inet, socket. SOCK_STREAM) Server_socket.bind (Ip_port) Server_socket.listen (5) Print (' Server start,ip:%s, LISTENING PORT:%s. ') % ip_port) Pool = Threadpoolexecutor (Ten) while true:conn, client_addr = Server_socket.accept () Print (' Create a new thread, and client {} communication '. Format (CLIENT_ADDR)) Pool.submit (take_over_connection, Conn, client_addr) def Take_over _connection (conn, client_addr): "" "is used to take over the socket link, each thread takes over a link:P Aram Conn::p Aram Client_address:: Return: "" "Print (' MyServer ') server = MyServer (conn, client_addr) Server.handle_cmd () class MyServer (object): "" "handles all client interactions with socket server" "STATUS = {: ' File not exist! ', 301: ' File exist, an D The msg include the file size! ', 302: ' File not exist!!! ' } def __init__ (self, conn, client_addr): Self.conn = conn self.client_addr = client_addr def handle_cm D (self): "" "Handles user command interaction: return:" "Print (' Handle_cmd ') whil E true:try: # received header length Recv_pack = SELF.CONN.RECV (4) if not RECV_PA Ck:print (' Connect {} is lost ... '. Format (Self.clien T_ADDR)) Break # parse Header recv_length = Struct.unpack (' i ', recv_pack) [0] Header_data = Self.conn.recv (recv_length) # Json_data json_data = json.loads (head Er_data.decode (' Utf-8 ')) print (' recv data >>> {} '. fOrmat (json_data)) Action_type = Json_data.get (' action_type ') if Action_type: # Use Reflection if Hasattr (self, ' _{} '. Format (Action_type)): Func = GetAttr (self, ' _{ } '. Format (Action_type)) func (json_data) else:print (' Invalid comm and ') except Connectionreseterror: # applies to Windows operating system break def send_response (self, status_cod E, **kwargs): "" "Send a response to the client:p Aram Status:: Return:" " "# constructs message header msg = {' Status ': Status_code, ' status_message ': self. Status.get (Status_code)} message.update (Kwargs) # update message Message_json = json.dumps (message) # To prevent sticky packets, encapsulate message Packets Header_byte = Message_json.encode (' Utf-8 ') # First sends the length of the header self.conn.send (struct.pack (' I ', Len (Message_json))) Print (' Send response reportLength of head: {} '. Format (len (Message_json))) print (' Send response header content: {} '. Format (message)) # Send header Self.conn.send (Header_byte) def _get (self, data): "" "Download file if file exists, send status code + file size +md5, send file does not exist, send status code:p Aram da TA:: Return: "" "Print (' _get {} '. Format (data)) File_path = Os.path.join (get_file_d IR, Data.get (' file_name ')) if Os.path.isfile (file_path): File_size = Os.path.getsize (file_pat h) Print (' File_path: {} file_size: {} '. Format (File_path, file_size)) Self.send_response (301, File_size=file_size, Md5=common_utils.get_md5 (file_path), Server_file_dir=os . Path.dirname (File_path)) print (' read to send file >>> ', Data.get (' file_name ')) with open (f Ile_path, ' RB ') as F:for line in F:self.conn.send (line) Else: Print (' Send fiLe {} done '. Format (File_path)) Else:self.send_response (302) def _put (self, data): "" " Get the file name and size, detect if the same file exists locally if present, create a new file Local_file_name+timestamp if present, create a new file Local_file_name:p Aram data: : Return: "" "Print (' _put {} '. Format (data)) File_size = Data.get (' file_size ') file_name = Data.get (' file_name ') File_path = Os.path.join (Put_file_dir, file_name) client_md5 = Data.get (' MD5 ') if Os.path.isfile (File_path): Print (' file is exist ') File_path = ' {}. {} '. Format (File_path, str (int (time.time ()))) Tmp_file = ' {}.down '. Format (file_path) print (' Tmp_file: ', Tmp_f ile) F = open (Tmp_file, ' WB ') recv_size = 0 print (' Put file {} start >>> '. Format (File_path) ) while recv_size < File_size:data = Self.conn.recv (8192) # Receive file contents F.write (data) Recv_size + = len (data) Else:print ("\ n") print ('--file [{}] put done, received size [{}] '. Format (file_n Ame, Common_utils.bytes2human (Os.path.getsize (tmp_file))) F.close () Os.rename (Tmp_file, File_path) Server_md5 = COMMON_UTILS.GET_MD5 (file_path) if server_md5 = = client_md5:print (' File upload Complete consistent with client ') if __name__ = = ' __main__ ': Run_forever ()
FTP Client
Import argparseimport socketimport jsonimport structimport sysimport osbase_dir = Os.path.dirname (Os.path.dirname ( Os.path.abspath (__file__)) Sys.path.append (Base_dir) from demo import Common_utilsput_file_path = R ' C:\x\LuffyFTP\ Sharefile\client\put ' Get_file_path = R ' C:\x\LuffyFTP\sharefile\client\get ' Ip_port = (' 127.0.0.1 ', 9999) class FtpClient (): "" "FTP Client" "" Def __init__ (self): Self.client_sock = None self.make_connect () d EF Make_connect (self): "" "Connect Server: Return:" "Try:self.client_sock = socket . Socket (socket.af_inet, socket. SOCK_STREAM) print (' Connection server ') Self.client_sock.connect (ip_port) # Connection server except Exception as E: Print (' Connection server exception ', E) def Interactive (self): "" "Interaction: Return:" "menu =" " "1. Download file get 1.txt 2. Upload file put 1.txt 3. Exit bye "" "Print (menu) while True:User_input = input (' Please enter >>> '). Strip () if not user_input:continue cmd_list = User_input.split () if hasattr (self, ' _{} '. Format (Cmd_list[0])): Func = GetAttr (self, ' _{} '. Mat (Cmd_list[0]) func (cmd_list) # Get Def send_msg (self, Action_type, **kwargs): "" "Package message, send to server:p Aram Action_type::p Aram Kwargs:: Return: "" "cmd = {' Action_ty PE ': Action_type,} cmd.update (Kwargs) # Update Dictionary Cmd_json = json.dumps (cmd) # to prevent sticky packets, Package H Eader_byte = Cmd_json.encode (' Utf-8 ') # First sends the length of the header self.client_sock.send (struct.pack (' I ', Len (Cmd_json))) Print (' Send Auth header length: {} '. Format (len (Cmd_json))) print (' Send Auth header content: {} '. Format (Cmd_json)) # Send header Self . Client_sock.send (Header_byte) def arg_check (self, Cmd_args, Len_args): If Len (cmd_args)! = Len_args: Print ('Must provide {} parameters but received {} '. Format (Len_args, Len (Cmd_args))) return False Else:return True def get_response (self): "" " Received a response from the server to the client: return: "" "# Received header length Recv_pack = Self.client_sock . recv (4) If Recv_pack: # parse Header recv_length = Struct.unpack (' i ', recv_pack) [0] Heade R_data = Self.client_sock.recv (recv_length) # Json_data json_data = json.loads (Header_data.decode (' U Tf-8 ') print (' recv response >>> {} '. Format (json_data)) return json_data else: Print (' Recv_pack is NULL!!! ') Return None def _get (self, Cmd_args): "" "Get file, send to remote, wait for return message, wait for file, loop to collect file:p Aram Cmd_args: : Return: "" "If Self.arg_check (Cmd_args, 2): file_name = cmd_args[1] # Get filename self.send_msg (' Get ', file_name=file_name) Response_data = Self.get_response () If Response_data.get (' status ') = = = 301:file_size = Response_data.get (' file_size ') serv ER_MD5 = Response_data.get (' MD5 ') File_path = Os.path.join (Get_file_path, file_name) recv_size = 0 p = self.progress_bar (file_size) # progress bar P.send (None) Print (' Get file {} start >>> '. Format (file_name)) Tmp_file = ' {}.down '. Format (File_path) With open (Tmp_file, ' WB ') as f: # write download File # Serialize save data while Recv_size < fil E_size:data = Self.client_sock.recv (8192) f.write (data) Recv_size + = len (data) p.send (recv_size) Else:print ( "\ n") Print ('--file [{}] recv done, received size [{}] '. Format (file_name, file_size)) If Os.path.isfile (file_path): # If file exists, overwrite file after deletion os.remove (file_path) Os.rename (tm P_file, file_path) client_md5 = COMMON_UTILS.GET_MD5 (file_path) if server_md5 = = Client_md5: Print (' File download complete and service-side consistent ') Else:print (Response_data.get (' status_message ')) de F _put (Self, Cmd_args): "" "1. Upload a local file to server 2. Make sure that the local file exists 3. send file name and file size to remote 4. Contents: R Eturn: "" "If Self.arg_check (Cmd_args, 2): Local_file_name = cmd_args[1] # put filename Full_path = Os.path.join (Put_file_path, Local_file_name) if Os.path.isfile (Full_path): Total_ Size = Os.path.getsize (full_path) self.send_msg (' Put ', file_name=loc Al_file_name, File_size=total_size, Md5=common_utils.get_md5 (full_path)) p = Self.progress_bar (total_size) P.send (None) upload_size = 0 with open (Full_path, ' RB ') as f: # send File For line on F:self.client_sock.send (line) Upload_size + = Len (line) P.send (upload_size) else:print ("\ n") Print (' File upload done '. Center () else:print (' file [{}] ' was not E Xist!!! '. Format (local_file_name)) def _bye (self, Cmd_args): "" "Exit: Return:" "" Print ("Bye") Self.client_sock.close () exit (0) @staticmethod def progress_bar (total_size): "" "Show progress bar :p Aram Total_size:: Return: "" "current_percent = 0 last_percent = 0 while True: ReCv_size = yield current_percent current_percent = Int (recv_size/total_size *) print ("#" * INT ( CURRENT_PERCENT/4) + ' {percent}% '. Format (Percent=int (current_percent)), end= "\ r", flush=true) if __name_ _ = = ' __main__ ': c = ftpclient () c.interactive ()
Common_util
Import loggingfrom Logging Import handlersimport osfrom tkinter import Tk, Filedialogimport osimport hashlibdef Bytes2huma N (N): # File size byte unit conversion symbols = (' K ', ' M ', ' G ', ' T ', ' P ', ' E ') prefix = {} for I, s in enumerate (symbols): # << left shift one means multiply by 2 = 1 << 1=2, two bits means 4 is 1 << 2=4, # 10 bits means 1024 is 1 << 10=1024 is 2 N-time PR Efix[s] = 1 << (i + 1) * for s in reversed (symbols): If n >= prefix[s]: value = float (n) /prefix[s] return '%.2f%s '% (value, s) return "%SB"% ndef get_md5 (file_path): "" "Get File MD5:p Aram File_path:: Return: "" "If Os.path.isfile (file_path): File_size = Os.stat (file_path). St_size md5_o BJ = HASHLIB.MD5 () # Hashlib f = open (File_path, ' RB ') # Opens file Read_size = 0 while read_size < fi Le_size:read_byte = F.read (8192) md5_obj.update (read_byte) # update MD5 read_size + = Le N (read_byte) hash_code = Md5_obj.hexdigest () # Get MD5 hexdigest f.close () print (' file: [{}] \nsize: [{}] \nmd5: [{}] '. forma T (File_path, Bytes2human (read_size), Hash_code)) return str (HASH_CODE) def get_dir_size_count (dir): " "" Gets the file size and number of files in the folder:p Aram dir:: Return: "" "size = 0 Count = 0 for root, dirs, and files in Os.walk (dir ): Size_li = [Os.path.getsize (Os.path.join (root, name)) for name in files] size + = SUM (siz E_li) Count + = Len (size_li) print (' directory {} file number {}, total size approximately {} '. Format (dir, Count, Bytes2human (size))) return count , Sizedef brows_local_filename (title= ' Choose a file ', Force=false): "" "Select a local file by FileDialog of Tkinter . Return an exist file path. :p Aram Title::p Aram force:if Force is True user must choose a file. : Return: "" "TK = TK () Tk.withdraw () tk.wm_attributes ('-topmost ', 1) while true:filename = Filedial Og.askopenfilename (Title=title) If not force or Filename:break Tk.destroy () return filenamedef brows_save_filename (title= ' Save As '): "" "Select a local path to save a file by FileDialog of Tkinter. Return a path for saving file. :p Aram Title:: Return: "" "TK = TK () Tk.withdraw () tk.wm_attributes ('-topmost ', 1) filename = FileDialog . Asksaveasfilename (Title=title) Tk.destroy () return filename
Python FTP File Transfer