First, the operation needs
Implementing concurrent Simple version FTP with select or selectors modules
Allow multiple users to upload and download files concurrently
Second, the README
The program realizes the following functions: 1, User login registration (test User: Japhi, Alex; password is 123) 2, upload/download files (already have sample files) 3, view different users own home directory under the file 4, The selector module is used to implement a single-threaded concurrency Effect client launcher: client_start.py Server Start Program: server_start.py
Iii. Description of the catalogue
Select ftp/|--Select ftpclient/ #客户端文件夹 | | --Sample Folder/ #客户端上传/Download Sample folder | | --client_start.py #客户端启动程序 | | --ftpserver/ #服务端文件夹 | | --bin/| | | --__init__.py| | | --server_start.py #程序启动的主入口 | | | | --conf/| | | --setting.py #配置文件 | | | | --db/ #用户数据 | | | --Alex #用户名alex的数据文件夹 | | | --Japhi #用户名japhi的数据文件夹 | | | | --home/| | | --alex/ #用户alex用户家目录 | | | --japhi/ #用户japhi用户家目录 | | | --log/| | --Log_sys.log #日志文件 | | --src/| | --__init__.py| | --common.py #公共函数功能 | | --main.py #程序主函数 | | --user.py #用户类及方法 | | --Ftp.png #流程图 |--README.txt
Iv. flowchart
V. Code Description 1, Select ftpclient/client_start.py
Import Socket,os,sys,timebasedir = Os.path.join (Os.path.dirname (Os.path.dirname (Os.path.abspath)), " Ftpserver ") Updir = Os.path.join (Os.path.dirname (Os.path.abspath (__file__))," Sample Folder ") Sys.path.append (Basedir) HOST = "localhost" PORT = 6960def Upload (client,user_info,name): "Client uploads a file function:p Aram Client:scoket client flag:p Aram User_ Info: Client Login User's information:p Aram Name: Client Login User's name: Return:none ' Print ("\033[1;37m currently selectable upload \033[0m". Center (+, "*")) dic = {} for root, dirs, files in Os.walk (Updir): For i,j in Enumerate (files): K = i+1 Dic[k] = J Print ("\033[1;37m%s:%s\033[0m"% (k,j)) choice = input ("Please enter the file number to be uploaded:>>>") command = "upload+" +user_info client.send (bytes (command,encoding= "Utf-8")) res = CLIENT.RECV (1024x768) if Str (res,encoding= "utf-8") = = " True ": dir = Os.path.join (updir,dic[int (choice)]) F = open (dir," RB ") data = f.read () length = STR (len (data)) Command2 = "Uploadfile+"+user_info+" + "+length+" + "+dic[int (choice)] Client.send (Command2.encode (" Utf-8 ")) Client.recv (1024) # Time.sleep (0.5) client.sendall (data) time.sleep (1) print ("\033[1;37m file Upload succeeded \033[0m") F.close () def download (client,user_info,name): "Client download file function:p Aram Client:scoket client flag:p Aram User_info: Client logged on user information :P Aram Name: Client Login user name: Return:none "dic = {} command =" download+ "+user_info client.sendall (bytes (com Mand, encoding= "Utf-8")) data = CLIENT.RECV (4069) res = eval (str (data, encoding= "Utf-8")) If Len (res) = = 0: Print ("\033[1;31m current directory has no file \033[0m". Center (1, "-")) Else:for I,j in Enumerate (res): K = i + Dic[k] = J Print ("\033[1;37m%s:%s\033[0m"% (k, j)) Choice = input ("Please select the file number to download:>>>") Command2 = "Downloadfile+" +user_info+ "+" +dic[int (choice)] Client.send (bytes (Command2, encoding= "Utf-8")) Print ("\033[1;37m ready to startDownload file \033[0m ") dir = Os.path.join (Updir, Dic[int (choice)]) Res_length = str (CLIENT.RECV (1024x768). Decode ()) # client.send ("True". Encode ("Utf-8")) #防止方式黏包 length = 0 f = open (dir, "WB") while length & Lt Int (res_length): If int (res_length)-length > 1024:size = 1024x768 Else: size = Int (res_length)-Length data = client.recv (size) Length + = Len (data) F.write ( data) if length = = Int (res_length): Time.sleep (1) print ("\033[1;37m File download successful \033[0m") F.close () def view_file (client,user_info,name): "Client view the function of the file in the current directory:p Aram client:scoket client flag:p Aram User_inf O: Client Login user Information:p Aram Name: Client Login user name: Return:none "command =" view+ "+user_info Client.sendall (bytes (CO mmand,encoding= "Utf-8")) data = CLIENT.RECV (1024x768) res = eval (str (data,encoding= "Utf-8")) If Len (res) = = 0: Print ("\033[1;31m currentNo files \033[0m ". Center (+,"-")) Else:for I in Res:print (" \033[1;35m%s\033[0m "%i) def operate (client , User_info,name): "Client operation main function:p Aram Client:scoket client flag:p Aram user_info: Client Login user Information:p Aram Name: Client Login User name: Return:none "dic = {" 1 ": Upload," 2 ":d ownload," 3 ": view_file} info =" '------operation instruction------1, upload file 2, Download file 3, view directory under File 4, exit "while True:print (" \033[1;33m%s\033[0m "% info) choice = input (" Please enter the Command:>>> "). Strip () if Choice.isdigit () and 0 < int (choice) <= len (DIC): Dic.get (choice) (CLI Ent,user_info,name) Elif choice.isdigit () and int (choice) = = 4:break Else:print ("\03 3[1;31m output Error \033[0m ". Center (+,"-")) def com_parse (client,com): ' Client user login registration hit resolution function:p Aram client: Clients scoket flag :p aram com: command: Return: Login successfully returns TRUE, otherwise false ' Client.sendall (Com.encode ("Utf-8")) Re = CLIENT.RECV (4096) I F Str (re,encoding= "Utf-8") = =" Success ": Return True elif str (RE, encoding=" utf-8 ") = =" Success ": Return falsedef Login (client,da TA): "Client User Login function:p Aram client: Scoket flag:p Aram Data: Return:none" "name = input (" Please enter your name :>>> "). Strip () PSD = input (" Please enter password:>>> "). Strip () User_info = name+" + "+psd com =" login+ "+user_in Fo if Com_parse (client,com): Print ("\033[1;31m login succeeded \033[0m") operate (client,user_info,name) Else: Print ("\033[1;31m login Exception \033[0m") def Register (client,data): ' Client user Registration function:p Aram client: Scoket flag:p Aram D ATA: Data: Return:none "name = input (" Please enter your name:>>> "). Strip () PSD = input (" Please enter password:>>> "). Strip () com = "register+" + name + "+" + PSD if com_parse (client, com): User_info = name + "+" + PSD print ( "\033[1;31m registered successfully \033[0m") Operate (client, User_info, name) else:print ("\033[1;31m Register Exception \033[0m") def quit ( Client,data): "'Program Exit Function:p Aram Client: Scoket flag:p Aram Data: User: Return:none ' exit () def main_func (client): ' Client-side Main Menu function:p Aram Client: Scoket flag:p Aram Data: Return:none "", "" The Connection succeeded "# Client.send (" suc Ceed ". Encode (" Utf-8 ")) dic = {" 1 ": Login," 2 ": Register," 3 ": quit} info =" '------User Login interface------*{0}* 1, Login 2, registration 3, exit ". Format (data) print (" \033[1;33m%s\033[0m "%info) what = input (" What are you doing? "). >>> "). Strip () if What.isdigit () and 0 < int (what) <= len (DIC): Dic.get (What) (Client,data) Else : Print ("\033[1;31m output error \033[0m". Center (+, "-")) if __name__ = = ' __main__ ': client = Socket.socket (Socket.af_inet, Socket. Sock_stream) Client.connect ((Host,port)) main_func (client) Client.close ()2. Select ftpserver/bin/server_start.py
Import Os,sysbase_dir = Os.path.dirname (Os.path.dirname (Os.path.abspath (__file__))) Sys.path.append (Base_dir) from Src.main import funcif __name__ = = ' __main__ ': func ()
3. Select ftpserver/conf/settings.py
Import Osbasedir = Os.path.dirname (Os.path.dirname (Os.path.abspath (__file__))) User_home = "%s/home"%basediruser_ info = "%s/db"%basedirlog_dir = Os.path.join (Basedir, "log") HOST = "localhost" PORT = 6960
4. Select ftpserver/src/common.py
Import logging,os,pickle,sys,uuidframe = Os.path.dirname (Os.path.dirname (Os.path.abspath (__file__))) Sys.path.append (frame) from conf import settingsdef sys_logging (content,levelname): ' Program logging function:p Aram content: Day Content:p Aram LevelName: Log level: Return:none ' _filename = Os.path.join (Settings.log_dir, "Log_sys.log") log = Logging.getlogger (_filename) logging.basicconfig (filename=_filename,level=logging.info,format= '% (asctime) s-% ( LevelName) s-% (message) s ', datefmt= '%m/%d/%y%i:%m:%s%p ') if levelname = = ' Debug ': Logging.debug (content) Eli F levelname = = ' Info ': logging.info (content) elif LevelName = = ' Warning ': logging.warning (content) Eli F levelname = = ' ERROR ': logging.error (content) elif LevelName = = ' critical ': logging.critical (content) def Show (Msg,msg_type): "Program different information print font color:p Aram msg: Print information:p Aram Msg_type: Type of printing information: Return:none ' if Msg_type = = "Info": show_msg = "\033[1;35m%s\033[0m "%msg elif msg_type = =" Error ": show_msg =" \033[1;31m%s\033[0m "%msg elif Msg_type = =" MSG ": Sho w_msg = "\033[1;37m%s\033[0m"%msg else:show_msg = "\033[1;32m%s\033[0m"%msg print (show_msg) sys_logging (M Sg,msg_type)
5. Select ftpserver/src/main.py
Import Socket,os,sys,selectorsbase_dir = Os.path.dirname (Os.path.dirname (Os.path.abspath (__file__))) Sys.path.append (Base_dir) from conf import settingsfrom src.common import showfrom src.user Import Usersel = selectors. Defaultselector () def accept (server, mask): "New linked callback function:p Aram Server: Service-side Instantiation object name:p Aram Mask: Number of Links: Return:non E ' Show (listening for [%s] address [%s] port, waiting for connection ... "% (settings. HOST, settings. PORT), "info") con, addr = Server.accept () Show ("received the connection request for {0}, in communication ... ". Format (addr)," info ") con.setblocking (False) sel.register (Con, selectors. Event_read, Server_method) def server_method (con,mask): "Service-side data parsing main function:p Aram Con::p Aram Addr:: return: "' # Try:cmd = Con.recv (1024x768) # print (cmd) if not cmd:sel.unregister (Con) con.close () Else : # print (cmd) data = Cmd.decode () res = Data.split ("+") name = res[1] psd = res[2] If res[0] = = "Login": Show ("Received client login request, logging in ... "," msg") user = User (name, PSD) sign = User.login () if Sign:con.sendall (bytes (" Success ", encoding=" Utf-8 ")) Else:con.sendall (bytes (" Failure ", encoding=" Utf-8 ")) Elif R Es[0] = = "Register": Show ("Received client registration request, registering ... "," msg ") user = User (name, PSD) if User.register (): Con.sendall (bytes (" Success ", enc oding= "Utf-8")) Else:con.sendall (bytes ("Failure", encoding= "Utf-8")) elif res[0] = = "Vie W ": Show (" Receive client requests to view current directory files ... "," msg ") user = User (name, PSD) res = user.view_file () file = str (res) con.se Ndall (bytes (file, encoding= "Utf-8")) Show ("Current directory file viewing success", "info") elif res[0] = = "Upload": Show ("A request to receive a client uploading a file ... "," MSG ") Con.send (bytes (" True ", encoding=" Utf-8 ")) elif res[0] = =" UploadFile ": Res_length = RES[3] filename = Res[4] # print (res_length) user.receive (filename, name, res_length, con) elif res[0] = = "Downloa D ": Show (" Request to receive client download file ...) "," msg ") user = User (name, PSD) res = str (user.view_file ()) Con.sendall (bytes (res, encod ing= "Utf-8")) elif res[0] = = "DownloadFile": filename = res[3] Show ("Start download File", "MSG") User.download_file (filename, name, con) show ("File download succeeded", "info") # except Exception as E: # Con.clos E () # Show ("Error:%s"%e, "error") def func (): "' Server main function: Return:none '" = Socket.socket (Socke T.af_inet,socket. SOCK_STREAM) Server.bind (settings. Host,settings. PORT) Server.listen (server.setblocking) (False) sel.register (server, selectors. Event_read, accept) while true:events = Sel.select () # Print (events) #11111111111 for Key,mask In events:callback = key.data # print (Key.data,"-----") Callback (Key.fileobj,mask) # Print (Key.fileobj, "-----", mask) 6. Select ftpserver/src/user.py
Import Os,sys,pickle,socket,timebase_dir = Os.path.dirname (Os.path.dirname (Os.path.abspath (__file__))) Sys.path.append (Base_dir) from conf import settingsfrom Src.common import Showclass User (object): ' User class ' d EF __init__ (SELF,USERNAME,PSD): Self.name = Username Self.password = PSD Self.home_path = settings.us Er_home + "/" +self.name def login (self): ' User Login method: return: ' ' user_dic = user.in Fo_read (Self.name) if user_dic[self.name] = = Self.password:show ("Login Successful", "info") return True Else:show ("Login failed, user name or password wrong", "error") return False def Register (self): "' User registration Method: return: ' dic = {} Dic[self.name] = Self.password if User.info_write (self.name,di c): Show ("Registered success", "info") Os.mkdir (Self.home_path) os.mkdir ("%s/others"% Self.home_path) With open ("%s\ blank file"% Self.home_paTh, "W") as F:f.write ("Blank file") return True else:show ("Registration failed", "error") Return False def view_file (self): "View files under current directory: return: List of filenames under directory" if not O S.path.exists (Self.home_path): Os.mkdir (Self.home_path) with open ("%s\ blank file"%self.home_path, "W") as F : F.write ("Blank file") for root, dirs, files in Os.walk (Self.home_path): Return files @stat ICMethod def download_file (filename,name,con): "Download file static method:p Aram FileName: file name:p Aram Nam E: username:p aram Con: flag: return:none "dir = Os.path.join (Os.path.join (Os.path.join, "Home"), name), filename) with open (dir, "RB") as F:data = F.read () length = str (len (data)) # Print (Type (a)) Con.sendall (bytes (length,encoding= "Utf-8")) Time.sleep (1) # C ON.RECV (1024) # Print (CON.RECV (1024x768). Decode ()) Con.sendall (data) @staticmethod def receive (Filename,name,res_length,co N): "Receive file static method:p Aram FileName: file name:p Aram Name: User name:p Aram Con: flag: Return:n One "Con.send" ("True". Encode ("Utf-8")) # print (filename) time.sleep (0.5) dir = Os.pat H.join (Os.path.join (Os.path.join (Base_dir, "Home"), name), filename) length = 0 f = open (dir, "WB") whi Le length < int (res_length): If int (res_length)-length > 1024:size = 1024x768 El se:size = Int (res_length)-Length data = con.recv (size) Length + = Len (data) # print (length) f.write (data) if length = = Int (res_length): time.sleep (0.5) SH ow ("File download succeeded", "info") F.close () return True @staticmethod def info_read (name): " static method of reading user data:p ARAm Name: Username: return: dictionary "user_dir = Os.path.join (settings.user_info,name) if os.path.exist S (user_dir): With open (User_dir, "RB") as F:dic = Pickle.load (f) return dic Else:print ("User data is empty") @staticmethod def info_write (name,dic): "The static method of writing user Data:p ar AM Name: User name:p Aram dic: User Information Dictionary: return:true ' user_dir = Os.path.join (Settings.user_info, Nam e) with open (User_dir, "WB") as F:pickle.dump (dic,f) return true#
Python path-Jobs: Select FTP (for reference only)