Implement a FTP+CRT with Python

Source: Internet
Author: User
Tags class definition

Reprint please specify the source http://www.cnblogs.com/Wxtrkbc/p/5590004.html

Originally the idea is to implement an FTP server, to implement the user login registration and file breakpoint upload download, and so on, the result is to do even the CRT also follow the completion, and then become such a ' nondescript ' tool. The knowledge used has hashlib encryption password transmission, object-oriented, Sockeserver support multi-client access, The os.subprocess handles the commands that come with the system, then customizes the upload and download commands, and how to implement the continuation of the breakpoint, the problem of sticky packets during transmission, and how to reflect the user's input. This is just for entertainment, let's take a look at

        

First, the client

First define a client class, roughly within the class definition of these methods, and later if necessary, you can expand it, the following class one initialization will go to execute the Start method, if the server registered login successful, then the Internet method will be executed, waiting for the user input,

Class Client:def __init__ (self, address): Self.address = Client.get_ip_port (address) Self.help_message =        [' Currently custom commands only support the following: \ n ' \tput|filename ', ' \tget|filename ',] Self.start () SELF.CWD = "@staticmethod def get_ip_port (address): IP, port = address.split (': ') return (IP , int (port)) def register (self): try_counts = 0 while try_counts < 3:user = input (' Please enter user name : ' If len (user) = = 0:continue passwd = input (' Please enter with password: ') if Len (passwd) = = 0:continue PD = hashlib.sha256 () pd.update (Passwd.encode ()) Self.socket . Sendall (' register|{}:{} '. Format (user, Pd.hexdigest ()). Encode ()) # Send encrypted account information ret = SELF.SOCKET.RECV (1024x768). Dec Ode () if ret = = ' 202 ': Print (' register successfully login ') Os.mkdir (Os.path.join (settings. User_home_dir, user) # on the client side also creates aUser home directory Os.mkdir (Os.path.join (settings. User_home_dir, user, ' Download_file ')) Os.mkdir (Os.path.join (settings. User_home_dir, user, ' Upload_file ')) return True else:try_counts + = 1 sys . Exit ("Too many attemps") def login (self): try_counts = 0 while try_counts < 3:user = InP UT (' Please enter user name: ') self.user = user If len (user) = = 0:continue passwd = input ( ' Please enter with password: ' If Len (passwd) = = 0:continue PD = hashlib.sha256 () pd.update (p            Asswd.encode ()) Self.socket.sendall (' login|{}:{} '. Format (user, Pd.hexdigest ()). Encode ()) # Send encrypted account information ret = SELF.SOCKET.RECV (1024x768). Decode () if ret = = ' $ ': print (' Login successful! ') SELF.CWD = Self.socket.recv (1024x768). Decode () return True ELSE:PR              Int (' User or password error, please re-login: ')  Try_counts + = 1 sys.exit ("Too many attemps") def Internet (self): pass<br> def process (self, C MD, argv): # Handle custom Commands pass<br> def help (Self, argv=none): Pass def put (auto, argv        =none): Pass def get (self, argv=none): Pass def start (self): Self.socket = Socket.socket () Try:self.socket.connect (self.address) except Exception as E:sys.exit ("Failed to Connec T server:%s "% E" print (SELF.SOCKET.RECV (1024x768). Decode ()) INP = input (' 1, registration, 2, login, 3, leave: ') if InP = = ' 1        ': If Self.register (): If Self.login (): # Interactive operation after successful login self.internet () elif INP = = ' 2 ': If Self.login (): Self.internet () else:sys.exit () if __n ame__ = = ' __main__ ': # address = input (' Please enter the FTP server address (Ip:port): ') address = ' 127.0.0.1:9999 ' client = Client (addres S
Second, the service side

Server is written with Socketserver, in order to come out multi-user requests, whenever the user comes to the request, first let its registration or login, after registration, to the user's name to create a home directory, and the user name and password to save, In the future when users log in from the DB to take out the data and user input password to compare, correct after the next operation, the user password entered three times after the exit program. Server in order to respond to each operation of the client, define a function specifically to accept the client from each command, and then decompose it, reflected to the specific server-specific function, where the need to first define the data sent by the client format is Cmd|args. You can see the data format (' login|{}:{} '. Format (user, pd.hexdigest ())) that I have on the client login authentication code. Here's how the code is done,

def handle (self):        Self.request.sendall (' Welcome to FTP server! '. Encode ()) while        True:            data = SELF.REQUEST.RECV (1024x768). Decode ()            if ' | ' in data:                cmd, argv = Data.split ( ' | ')            else:                cmd = data                argv = None            self.process (cmd, argv)  # will accept the moral data out after the process    def process (self, cmd , Argv=none):  # Use reflection to handle commands passed by the client (custom command)        if hasattr (self, cmd):            func = GetAttr            argv)        else:            Pass

After such a write, just on the server write the corresponding function, for example, register, I just write a function called Register function, specifically to deal with the registration, the same kind of landing, I just write a login function, the first time I write, are used If,else to judge, At that time, the code written down, I looked at all the horror, writing, I do not know where to judge, think about the tears. With reflection, you do not need these tedious steps, and in the future to add functionality, you just need to write a simple function. The client's reflection also does this, and it is no longer duplicated.

Third, breakpoint upload

If it is just file upload, it is better to write, but if you want to upload a breakpoint, there is some trouble, here to provide a way of thinking, that is, the service side record the size of the file, the next time you upload, if you want to continue the upload, the uploaded file size to the client, and then the client from the location of the breakpoint Here's a look at the implementation of the Code,

# Client def put (self, argv=none): If Len (argv) = = None:print ("Please add the file path so you want to up Load ") return print (' Make sure the file is in the user upload folder before uploading ') File_path = Os.path.join (settings. User_home_dir, Self.user, ' Upload_file ', argv) if Os.path.exists (file_path): #判断文件存不存在 file_size = OS             . Stat (File_path). st_size file_info = {' file_name ': argv, ' file_size ': file_size, } has_sent = 0 self.socket.sendall (' put|{} '.            Format (Json.dumps (File_info))). Encode () # sends the uploaded file information as a parameter to the service-side ret = SELF.SOCKET.RECV (1024x768). Decode () if ret = = ' 204 ': INP = input ("The file exists, does it continue?")                    y/n: "). Strip () if inp.upper () = =" Y ": Self.socket.sendall (' 205 '. Encode ()) has_sent = Int (SELF.SOCKET.RECV (1024x768). Decode ()) Else:self.socket.sendall (' 207 '. Enc Ode ()) with open (File_path, ' RB ') as F:f.seek (has_sent) # If you want to continue, Has_set is the size of the upload, otherwise has_set is 0, upload from the beginning                    For line on F:self.socket.sendall (line) has_sent + = Len (line)                    k = Int ((has_sent/file_size * 100)) # The following code is used to display the progress bar Table_space = (100-k) * " Flag = k * ' * ' time.sleep (0.05) sys.stdout.write (' \r{} {:. 0%} '. Format ((flag + TA Ble_space), (has_sent/file_size))) print () # shows the effect of line breaks

Look at the service side of the code, the server and the client are a receive, note to keep recv to receive information, otherwise it will block, in addition to the time of transmission may occur sticky packet, the solution is to send a file file, first send a flag message, when the server received the flag information, You can notify the client to send the file.

# server def put (self, argv=none): File_info = Json.loads (argv) # Get the message from the client file_name = file_info[' fil E_name '] file_size = Int (file_info[' file_size ')) File_path = Os.path.join (settings.            User_home_dir, ' Kobe ', ' upload_file ', file_name) have_send = 0 # already uploaded position if os.path.exists (File_path):  Self.request.sendall (' 204 '. Encode ()) ret = SELF.REQUEST.RECV (1024x768). Decode () if ret = = ' 205 ': # continuation have_send = Os.stat (File_path). St_size # Gets the size of the uploaded file Self.request.sendall (bytes (s                  TR (have_send), encoding= ' Utf-8 ')) F = open (File_path, ' AB ') # to continue the word, open the file in a mode, else: f = open (File_path, ' WB ') # does not renew the words, opened in W mode, Else:self.request.sendall (' 206 '. E              Ncode ()) # Direct Upload f = open (File_path, ' WB ') while true:if have_send = = File_size:              # Once the received content equals the file size, exit the loop directly    Break Try:ret = SELF.REQUEST.RECV (1024x768) except Exception as E:br Eak f.write (ret) Have_send + = Len (ret)

To resolve the continuation of the break, then the breakpoint download is the same reason, will not repeat the talk.

4. CRT

Finally, how to implement remote operation Server host, here is for entertainment. In fact, it is relatively simple to realize. The main use of subprocess.getoutput get to handle the client input command, and then return the results to the client can, but there is a fatal flaw, that is not supported CD command, if not support CD command, that also talk about remote operation, so here for CD command need special treatment, solve the Approach, of course, is to find a support CD command, below to see the server side of the large code

def process (self, cmd, argv=none):  # Use reflection to handle the command passed by the client (custom command)        if Hasattr (the. cmd):            func = getattr CMD)            func (argv)        else:            if Cmd.startswith (' CD '):            # (Process CD command, subprocess does not support CD command)                Os.chdir ( Cmd.split (") [1]) # Get the parameters of the CD command, hand it to os.chdir to switch directories                pass                         else:                data = Subprocess.getoutput (cmd) # Other commands, to SUBP Rocess processing,                data_length = len (data)                if data_length! = 0:                    pass                else:                    Pass

After processing the relevant commands, the results will be returned to the client display. Finally, the client saves a variable that is used to save the current execution path as shown, like [C:\Users\Tab\PycharmProjects\myftp\New_ftp\New_Server]: So.

V. Summary

Here, basically the key things are finished, the others are some simple operation, as long as you pay attention to a bit, you can write a similar thing.

  

  

Implement a FTP+CRT with Python

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.