用AI开发软件:FTP管理工具(附完整代码)
在当今快速发展的技术世界中,人工智能(AI)正在改变我们开发软件的方式。无论是代码生成、问题调试,还是架构设计,AI工具都能为开发者提供强大的支持。今天,我们将探索如何利用AI开发一个简单的FTP(文件传输协议)工具,并附上完整的代码实现。
技术栈
当前功能
- 多IP地址自动检测
- 实时连接数统计
- 细粒度权限控制
- 操作日志记录
软件截图
完整代码(单文件)
代码完全根据个人习惯和喜好进行编写;大家可以根据代码中包含的各项注释进行阅读或修改。
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
import threading
import socket
import webbrowser
from typing import List
class FTPServerGUI:
def __init__(self, root):
self.root = root
self.server = None
self.connection_count = 0
self.setup_ui()
self.show_filtered_ips()
self.display_welcome_msg()
def setup_ui(self):
self.root.title("FTP服务器 v1.0")
self.root.geometry("560x500")
self.root.minsize(560, 480)
self.root.columnconfigure(0, weight=1)
self.root.columnconfigure(1, weight=1)
self.root.rowconfigure(4, weight=1)
top_info = ttk.Frame(self.root)
top_info.grid(row=0, column=0, columnspan=2, padx=10, pady=5, sticky="ew")
self.conn_label = ttk.Label(top_info, text="当前连接: 0", foreground="green")
self.conn_label.pack(side="right", padx=10)
ttk.Label(top_info, text="服务器IP:").pack(side="left")
self.ip_label = ttk.Label(top_info, text="正在获取...", foreground="blue")
self.ip_label.pack(side="left", padx=5)
config_frame = ttk.LabelFrame(self.root, text="服务器配置")
config_frame.grid(row=1, column=0, columnspan=2, padx=10, pady=5, sticky="ew")
input_grid = ttk.Frame(config_frame)
input_grid.pack(fill="x", padx=5, pady=5)
ttk.Label(input_grid, text="端口:").grid(row=0, column=0, padx=5, sticky="w")
self.port_entry = ttk.Entry(input_grid, width=8)
self.port_entry.grid(row=0, column=1, sticky="w")
self.port_entry.insert(0, "21")
ttk.Label(input_grid, text="用户:").grid(row=0, column=2, padx=(15,5), sticky="w")
self.user_entry = ttk.Entry(input_grid, width=12)
self.user_entry.grid(row=0, column=3, sticky="w")
self.user_entry.insert(0, "user")
ttk.Label(input_grid, text="密码:").grid(row=0, column=4, padx=(15,5), sticky="w")
self.pass_entry = ttk.Entry(input_grid, width=12, show="*")
self.pass_entry.grid(row=0, column=5, sticky="w")
self.pass_entry.insert(0, "123")
dir_frame = ttk.Frame(config_frame)
dir_frame.pack(fill="x", padx=5, pady=5)
ttk.Button(dir_frame, text="选择FTP目录", command=self.select_directory).pack(side="left")
self.dir_label = ttk.Label(dir_frame, text="未选择目录", foreground="gray")
self.dir_label.pack(side="left", padx=10)
perm_frame = ttk.LabelFrame(self.root, text="用户权限设置")
perm_frame.grid(row=2, column=0, columnspan=2, padx=10, pady=5, sticky="nsew")
self.perm_vars = {
'e': tk.BooleanVar(value=True),
'l': tk.BooleanVar(value=True),
'r': tk.BooleanVar(value=True),
'a': tk.BooleanVar(),
'd': tk.BooleanVar(),
'f': tk.BooleanVar(),
'm': tk.BooleanVar(value=True),
'M': tk.BooleanVar(),
'w': tk.BooleanVar(value=True),
}
cols = [ttk.Frame(perm_frame) for _ in range(3)]
for i, col in enumerate(cols):
col.grid(row=0, column=i, sticky="nsew", padx=5)
perm_frame.columnconfigure(i, weight=1)
permissions = [
("上传文件 (w)", 'w', 0),
("下载文件 (r)", 'r', 0),
("删除文件 (d)", 'd', 0),
("查看列表 (l)", 'l', 1),
("切换目录 (e)", 'e', 1),
("创建目录 (m)", 'm', 1),
("修改权限 (M)", 'M', 2),
("重命名 (f)", 'f', 2),
("追加文件 (a)", 'a', 2)
]
for text, key, col_idx in permissions:
ttk.Checkbutton(cols[col_idx], text=text, variable=self.perm_vars[key]).pack(anchor="w", pady=2)
btn_frame = ttk.Frame(self.root)
btn_frame.grid(row=3, column=0, columnspan=2, pady=10)
self.start_btn = ttk.Button(btn_frame, text="启动服务器", command=self.toggle_server)
self.start_btn.pack(side="left", padx=5)
log_frame = ttk.LabelFrame(self.root, text="服务器日志")
log_frame.grid(row=4, column=0, columnspan=2, padx=10, pady=5, sticky="nsew")
self.log_text = scrolledtext.ScrolledText(log_frame, wrap=tk.WORD, height=8)
self.log_text.pack(expand=True, fill="both")
blog_link = ttk.Label(self.root, text="zneVue & AI", foreground="blue", cursor="hand2")
blog_link.grid(row=5, column=1, padx=10, pady=5, sticky="se")
blog_link.bind("<Button-1>", lambda e: webbrowser.open("https://www.52pojie.cn/home.php?mod=space&uid=2299786"))
perm_frame.rowconfigure(0, weight=1)
log_frame.rowconfigure(0, weight=1)
log_frame.columnconfigure(0, weight=1)
def show_filtered_ips(self) -> List[str]:
try:
ips = socket.gethostbyname_ex(socket.gethostname())[2]
filtered_ips = [
ip for ip in ips
if ip != "127.0.0.1"
and not ip.startswith("169.254.")
]
self.ip_label.config(text=", ".join(filtered_ips) if filtered_ips else "未找到有效IP")
return filtered_ips
except Exception as e:
self.ip_label.config(text=f"获取IP失败: {str(e)}")
return []
def is_valid_ip(self, ip: str) -> bool:
if ip.startswith("127.") or ip == "::1":
return False
if ip.startswith("169.254."):
return False
if ip.startswith("172.17."):
return False
if ip.startswith("192.168.") or ip.startswith("10."):
return True
return True
def select_directory(self):
directory = filedialog.askdirectory()
if directory:
self.dir_label.config(text=directory, foreground="black")
def update_connection_count(self, delta: int):
"""线程安全更新连接数"""
self.connection_count += delta
self.root.after(0, self.conn_label.config,
{"text": f"当前连接: {self.connection_count}"})
def log_message(self, msg: str):
self.log_text.insert(tk.END, msg + "\n")
self.log_text.see(tk.END)
def thread_safe_log(self, msg: str):
self.root.after(0, self.log_message, msg)
def toggle_server(self):
if self.server is None:
self.start_server()
else:
self.stop_server()
def start_server(self):
port = int(self.port_entry.get())
user = self.user_entry.get()
password = self.pass_entry.get()
directory = self.dir_label.cget("text")
if not all([user, password, directory]) or directory == "未选择目录":
messagebox.showerror("错误", "请填写所有必填字段!")
return
perm = ''.join([k for k, v in self.perm_vars.items() if v.get()])
if not perm:
messagebox.showerror("错误", "请至少选择一个权限!")
return
class CustomHandler(FTPHandler):
gui = self
def on_connect(self):
self.gui.update_connection_count(1)
self.gui.thread_safe_log(f"[连接] {self.remote_ip}:{self.remote_port} 已连接")
def on_disconnect(self):
self.gui.update_connection_count(-1)
self.gui.thread_safe_log(f"[连接] {self.remote_ip}:{self.remote_port} 断开连接")
def on_login(self, username):
self.gui.thread_safe_log(f"[认证] 用户 {username} 登录成功")
def on_login_failed(self, username, password):
self.gui.thread_safe_log(f"[认证] 登录失败 用户名: {username}")
try:
authorizer = DummyAuthorizer()
authorizer.add_user(user, password, directory, perm=perm)
handler = CustomHandler
handler.authorizer = authorizer
self.server = FTPServer(("0.0.0.0", port), handler)
self.thread_safe_log(f"[状态] 服务已启动于 0.0.0.0:{port}")
self.thread_safe_log(f"[提示] 可用地址: {self.ip_label.cget('text')}")
self.start_btn.config(text="停止服务器")
server_thread = threading.Thread(target=self.server.serve_forever)
server_thread.daemon = True
server_thread.start()
except Exception as e:
self.thread_safe_log(f"[错误] 启动失败: {str(e)}")
def stop_server(self):
if self.server:
self.server.close_all()
self.server = None
self.connection_count = 0
self.conn_label.config(text="当前连接: 0")
self.thread_safe_log("[状态] 服务器已停止")
self.start_btn.config(text="启动服务器")
def display_welcome_msg(self):
"""显示欢迎信息"""
welcome_text = """=== FTP服务器 v1.0 ===
【使用指南】
1. 选择FTP目录 -> 设置用户权限 -> 启动服务
2. 客户端连接地址显示在顶部IP栏
3. 日志区域实时显示连接状态
【常用命令帮助】
USER [用户名] - 登录认证
PASS [密码] - 输入密码
LIST - 列出文件列表
RETR [文件名] - 下载文件
STOR [文件名] - 上传文件
QUIT/EXIT - 断开连接
当前版本功能:
• 多IP地址自动检测
• 实时连接数统计
• 细粒度权限控制
• 操作日志记录
"""
self.log_text.configure(state='normal')
self.log_text.delete(1.0, tk.END)
self.log_text.insert(tk.END, welcome_text)
self.log_text.tag_configure("title", foreground="#2E75B6", font=('微软雅黑', 10, 'bold'))
self.log_text.tag_add("title", "1.0", "1.19")
if __name__ == "__main__":
root = tk.Tk()
app = FTPServerGUI(root)
root.mainloop()