最新源码请在 GitHub 查看。
使用 tkinter 实现 FTP 服务器桌面软件
实现功能:
- 可以修改有权限的用户名、密码及端口
- 匿名用户访问只能浏览
- 可以修改路径,弹出文件夹选择窗口
- 启动和停止按钮可以交互显示
- 对文件夹路径做判断,不合理的会有提示
运行界面如下:
直接贴代码:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- """FTP服务器GUI""" import os import sys from tkinter import (Button, Entry, Frame, Label, StringVar, Tk, filedialog, messagebox) from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler from pyftpdlib.servers import FTPServer, ThreadedFTPServer import _thread class FTP(Tk): def __init__(self): Tk.__init__(self) self.title("FTP服务器GUI") self.set_window_center(self, 300, 180) self.resizable(False, False) self.server = None self.server_thread = None self.running = StringVar(value="normal") self.var_username = StringVar(value="doudou") self.var_passwd = StringVar(value="doudou") self.var_address = StringVar(value="127.0.0.1") self.var_port = StringVar(value="3333") self.var_path = StringVar(value=".") # 默认路径 self.entry_username = None self.entry_passwd = None self.entry_address = None self.entry_port = None self.entry_path = None self.load_view() def run_ftp(self): if os.path.isdir(self.var_path.get()) is not True: messagebox.showerror(title="提示", message="路径不对", parent=self) return _thread.start_new_thread(self.ftpserver, ()) self.fixed_entry("readonly") def stop_ftp(self): self.fixed_entry() if self.server: try: self.server.close() except Exception: print(Exception) def ftpserver(self): # 实例化虚拟用户,这是FTP验证首要条件 authorizer = DummyAuthorizer() # 添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限) authorizer.add_user( self.var_username.get(), self.var_passwd.get(), self.var_path.get(), perm="elradfmwMT") # 添加匿名用户,任何人都可以访问,否则需要输入用户名和密码才能访问 # 匿名用户只需要配置路径 authorizer.add_anonymous(self.var_path.get(), msg_login="Welcome") # 初始化ftp句柄 handler = FTPHandler handler.authorizer = authorizer # 监听ip和端口 self.server = ThreadedFTPServer( (self.var_address.get(), self.var_port.get()), handler) # 开始服务 self.server.serve_forever() def load_view(self): """界面""" Label(self, text="账号:").grid(column=0, row=0, sticky="nswe") self.entry_username = Entry(self, textvariable=self.var_username, bd=2) self.entry_username.grid(column=1, row=0, columnspan=2, sticky="nswe") Label(self, text="密码:").grid(column=0, row=1, sticky="nswe") self.entry_passwd = Entry(self, textvariable=self.var_passwd, bd=2) self.entry_passwd.grid(column=1, row=1, columnspan=2, sticky="nswe") Label(self, text="地址:").grid(column=0, row=2, sticky="nswe") self.entry_address = Entry(self, textvariable=self.var_address, bd=2) self.entry_address.grid(column=1, row=2, columnspan=2, sticky="nswe") Label(self, text="端口:").grid(column=0, row=3, sticky="nswe") self.entry_port = Entry(self, textvariable=self.var_port, bd=2) self.entry_port.grid(column=1, row=3, columnspan=2, sticky="nswe") Label(self, text="路径:").grid(column=0, row=4, sticky="nswe") self.entry_path = Entry(self, textvariable=self.var_path, bd=2) self.entry_path.grid(column=1, row=4) self.btn_select_path = Button(self, text="选择", command=self.selectPath) self.btn_select_path.grid(column=2, row=4) btn_box = Frame(self, relief="ridge", borderwidth=0, bd=2) btn_box.grid(column=0, row=5, columnspan=3, sticky="nswe") self.btn_start = Button(btn_box, text="启动", command=self.run_ftp) self.btn_start.pack(side="left") self.btn_stop = Button( btn_box, text="停止", command=self.stop_ftp, state="disable") self.btn_stop.pack(side="left") def selectPath(self): path = filedialog.askdirectory() if os.path.isdir(path): self.var_path.set(path) def fixed_entry(self, state="normal"): s = "readonly" if (state == "readonly") else "normal" a = "disable" if (state == "readonly") else "normal" self.entry_username["state"] = s self.entry_passwd["state"] = s self.entry_address["state"] = s self.entry_port["state"] = s self.entry_path["state"] = s self.btn_select_path["state"] = a self.btn_start["text"] = "运行中" if (state == "readonly") else "启动" self.btn_start["state"] = a self.btn_stop["state"] = "normal" if ( state == "readonly") else "disable" def set_window_center(self, window, width, height): """设置窗口宽高及居中""" # 获取屏幕 宽、高 w_s = window.winfo_screenwidth() h_s = window.winfo_screenheight() # 计算 x, y 位置 x_co = (w_s - width) / 2 y_co = (h_s - height) / 2 - 50 window.geometry("%dx%d+%d+%d" % (width, height, x_co, y_co)) window.minsize(width, height) if __name__ == "__main__": ftp = FTP() ftp.mainloop()