You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1097 lines
39 KiB

import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext, filedialog
import threading
import subprocess
import os
import sys
import time
import random
import subprocess
from subprocess import CREATE_NO_WINDOW, STARTUPINFO, STARTF_USESHOWWINDOW
class FileTransferApp:
def __init__(self, root):
self.root = root
self.root.title("蜗牛创造的高速文件传输")
self.root.geometry("900x700")
self.root.configure(bg='white') # 设置窗口背景为白色
# 设置样式
self.setup_styles()
# 创建主框架容器
self.main_frame = tk.Frame(self.root, bg='white')
self.main_frame.pack(fill='both', expand=True, padx=20, pady=20)
# 显示欢迎界面
self.show_welcome_screen()
def setup_styles(self):
"""设置界面样式"""
style = ttk.Style()
style.configure('TButton', font=('Microsoft YaHei', 10))
style.configure('Primary.TButton', background='#3498db', foreground='white')
style.configure('Success.TButton', background='#2ecc71', foreground='white')
style.configure('Danger.TButton', background='#e74c3c', foreground='white')
style.configure('Secondary.TButton', background='#95a5a6', foreground='white')
def clear_frame(self):
"""清除当前框架中的所有控件"""
for widget in self.main_frame.winfo_children():
widget.destroy()
def show_welcome_screen(self):
"""显示欢迎界面"""
self.clear_frame()
# 顶部logo区域
logo_frame = tk.Frame(self.main_frame, bg='white')
logo_frame.pack(pady=(30, 20))
# 欢迎标签
welcome_label = tk.Label(
logo_frame,
text="🐌 欢迎来到蜗牛创造的高速世界",
font=("Microsoft YaHei", 20, "bold"),
fg="#2c3e50",
bg='white'
)
welcome_label.pack()
# 副标题
subtitle_label = tk.Label(
logo_frame,
text="安全、高速的文件传输解决方案",
font=("Microsoft YaHei", 12),
fg="#7f8c8d",
bg='white'
)
subtitle_label.pack(pady=(5, 30))
# 功能卡片框架
card_frame = tk.Frame(self.main_frame, bg='white')
card_frame.pack(pady=20)
# 发送卡片
send_card = tk.Frame(card_frame, bg='#f8f9fa', relief='raised', bd=1, padx=20, pady=20)
send_card.pack(side='left', padx=15)
send_icon = tk.Label(send_card, text="📤", font=("Arial", 24), bg='#f8f9fa')
send_icon.pack()
send_title = tk.Label(send_card, text="发送文件", font=("Microsoft YaHei", 14, "bold"), fg="#2c3e50", bg='#f8f9fa')
send_title.pack(pady=(10, 5))
send_desc = tk.Label(send_card, text="快速安全地发送文件", font=("Microsoft YaHei", 9), fg="#7f8c8d", bg='#f8f9fa')
send_desc.pack(pady=(0, 15))
send_button = tk.Button(
send_card,
text="开始发送",
command=self.show_send_screen,
font=("Microsoft YaHei", 11, "bold"),
bg="#3498db",
fg="white",
width=12,
height=2,
relief='flat',
cursor='hand2'
)
send_button.pack()
# 接收卡片
receive_card = tk.Frame(card_frame, bg='#f8f9fa', relief='raised', bd=1, padx=20, pady=20)
receive_card.pack(side='left', padx=15)
receive_icon = tk.Label(receive_card, text="📥", font=("Arial", 24), bg='#f8f9fa')
receive_icon.pack()
receive_title = tk.Label(receive_card, text="接收文件", font=("Microsoft YaHei", 14, "bold"), fg="#2c3e50", bg='#f8f9fa')
receive_title.pack(pady=(10, 5))
receive_desc = tk.Label(receive_card, text="安全可靠地接收文件", font=("Microsoft YaHei", 9), fg="#7f8c8d", bg='#f8f9fa')
receive_desc.pack(pady=(0, 15))
receive_button = tk.Button(
receive_card,
text="开始接收",
command=self.show_receive_screen,
font=("Microsoft YaHei", 11, "bold"),
bg="#2ecc71",
fg="white",
width=12,
height=2,
relief='flat',
cursor='hand2'
)
receive_button.pack()
# 网盘加速卡片
cloud_card = tk.Frame(card_frame, bg='#f8f9fa', relief='raised', bd=1, padx=20, pady=20)
cloud_card.pack(side='left', padx=15)
cloud_icon = tk.Label(cloud_card, text="", font=("Arial", 24), bg='#f8f9fa')
cloud_icon.pack()
cloud_title = tk.Label(cloud_card, text="网盘加速", font=("Microsoft YaHei", 14, "bold"), fg="#2c3e50", bg='#f8f9fa')
cloud_title.pack(pady=(10, 5))
cloud_desc = tk.Label(cloud_card, text="加速您的网盘访问", font=("Microsoft YaHei", 9), fg="#7f8c8d", bg='#f8f9fa')
cloud_desc.pack(pady=(0, 15))
cloud_button = tk.Button(
cloud_card,
text="加速服务",
command=self.show_cloud_accel_screen,
font=("Microsoft YaHei", 11, "bold"),
bg="#f39c12",
fg="white",
width=12,
height=2,
relief='flat',
cursor='hand2'
)
cloud_button.pack()
# 底部信息
footer_frame = tk.Frame(self.main_frame, bg='white')
footer_frame.pack(side='bottom', pady=20)
footer_label = tk.Label(
footer_frame,
text="© 2025 蜗牛创造 - 让文件传输更简单",
font=("Microsoft YaHei", 9),
fg="#bdc3c7",
bg='white'
)
footer_label.pack()
def show_cloud_accel_screen(self):
"""显示网盘加速界面"""
self.clear_frame()
# 标题栏
title_frame = tk.Frame(self.main_frame, bg='white')
title_frame.pack(fill='x', pady=(10, 20))
back_button = self.create_styled_button(title_frame, "← 返回", self.show_welcome_screen, "#95a5a6", 8)
back_button.pack(side='left')
title_label = tk.Label(
title_frame,
text="⚡ 网盘加速服务",
font=("Microsoft YaHei", 16, "bold"),
fg="#2c3e50",
bg='white'
)
title_label.pack(side='left', padx=10)
# 说明文本
desc_frame = tk.Frame(self.main_frame, bg='white')
desc_frame.pack(fill='x', pady=(0, 20))
desc_text = """功能说明:
• 为KodCloud等网盘提供加速服务
• 使用XTCP协议建立高速通道
• 本地端口: 8089
• 服务器: 127.0.0.1"""
desc_label = tk.Label(
desc_frame,
text=desc_text,
font=("Microsoft YaHei", 10),
fg="#7f8c8d",
bg='white',
justify='left'
)
desc_label.pack(anchor='w')
# 按钮组
button_frame = tk.Frame(self.main_frame, bg='white')
button_frame.pack(pady=20)
self.cloud_start_button = self.create_styled_button(button_frame, "🚀 启动加速", self.start_cloud_accel, "#27ae60", 15)
self.cloud_start_button.pack(side='left', padx=10)
self.cloud_stop_button = self.create_styled_button(button_frame, "⏹️ 停止加速", self.stop_cloud_accel, "#e74c3c", 15)
self.cloud_stop_button.pack(side='left', padx=10)
self.cloud_stop_button.config(state='disabled')
# 状态显示
status_frame = tk.Frame(self.main_frame, bg='white')
status_frame.pack(fill='x', pady=5)
self.cloud_status_label = tk.Label(
status_frame,
text="📊 状态: 等待启动加速服务",
font=("Microsoft YaHei", 10),
fg="#7f8c8d",
bg='white'
)
self.cloud_status_label.pack()
# 输出区域
output_card = tk.Frame(self.main_frame, bg='#f8f9fa', relief='raised', bd=1, padx=15, pady=15)
output_card.pack(fill='both', expand=True, pady=(10, 0))
output_label = tk.Label(output_card, text="📋 加速服务日志:", font=("Microsoft YaHei", 10), bg='#f8f9fa')
output_label.pack(anchor='w')
self.cloud_output = scrolledtext.ScrolledText(
output_card,
height=12,
width=80,
font=("Consolas", 9),
state='disabled',
relief='solid',
bd=1,
bg='#ffffff'
)
self.cloud_output.pack(fill='both', expand=True, pady=(5, 0))
# 初始信息
self.append_cloud_output("网盘加速服务就绪\n")
self.append_cloud_output("点击「启动加速」开始服务\n")
# 进程引用
self.cloud_process = None
self.is_cloud_running = False
def create_kodcloud_ini(self):
"""创建kodcloud.ini配置文件"""
# 获取当前时间,精确到秒
from datetime import datetime
current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
ini_content = f"""[common]
local_ip = 0.0.0.0
server_addr = 47.97.6.201
server_port = 7100
token = ENbOUMvXJGWuA623@@@
[kodcloud_{current_time}]
type = xtcp
role = visitor
server_name = M0BUnkgzPxR0Ebdp9NQ4VUtm4EpTDvPR1
sk = aw1fohFnPcZEjRcRogENJzBbgPsNqjV31
bind_ip = 127.0.0.1
bind_port = 8089
"""
try:
with open('./kodcloud.ini', 'w', encoding='utf-8') as f:
f.write(ini_content)
self.append_cloud_output(f"✅ 配置文件 kodcloud.ini 创建成功\n")
self.append_cloud_output(f"✅ 时间标识: {current_time}\n")
return True
except Exception as e:
self.append_cloud_output(f"❌ 创建配置文件失败: {e}\n")
return False
def monitor_cloud_output(self):
"""监控网盘加速输出"""
try:
for line in iter(self.cloud_process.stdout.readline, ''):
if not self.is_cloud_running:
break
if line:
self.append_cloud_output(f"[加速服务] {line}")
except:
pass
def start_cloud_accel(self):
"""启动网盘加速服务"""
try:
# 创建配置文件
if not self.create_kodcloud_ini():
return
self.cloud_process = subprocess.Popen(
['.\\gc.exe', '-c', '.\\kodcloud.ini'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding='utf-8',
errors='replace',
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
# 更新状态
self.is_cloud_running = True
self.cloud_start_button.config(state='disabled')
self.cloud_stop_button.config(state='normal')
self.cloud_status_label.config(text="📊 状态: 加速服务运行中", fg="#27ae60")
self.append_cloud_output("🚀 启动网盘加速服务...\n")
self.append_cloud_output("📍 本地访问地址: http://127.0.0.1:8089\n")
# 启动输出监控线程
output_thread = threading.Thread(target=self.monitor_cloud_output, daemon=True)
output_thread.start()
except Exception as e:
self.append_cloud_output(f"❌ 启动加速服务失败: {e}\n")
def stop_cloud_accel(self):
"""停止网盘加速服务"""
self.is_cloud_running = False
self.cloud_status_label.config(text="📊 状态: 正在停止服务", fg="#e74c3c")
if self.cloud_process and self.cloud_process.poll() is None:
try:
self.cloud_process.terminate()
self.append_cloud_output("⏹️ 正在停止加速服务...\n")
except:
pass
time.sleep(1)
self.cloud_start_button.config(state='normal')
self.cloud_stop_button.config(state='disabled')
self.cloud_status_label.config(text="📊 状态: 服务已停止", fg="#7f8c8d")
self.append_cloud_output("✅ 加速服务已停止\n")
def append_cloud_output(self, message):
"""向网盘加速输出框添加消息"""
self.cloud_output.config(state='normal')
self.cloud_output.insert(tk.END, message)
def create_styled_button(self, parent, text, command, bg_color, width=10):
"""创建样式统一的按钮"""
return tk.Button(
parent,
text=text,
command=command,
font=("Microsoft YaHei", 10, "bold"),
bg=bg_color,
fg="white",
width=width,
relief='flat',
cursor='hand2',
padx=10,
pady=5
)
def show_send_screen(self):
"""显示发送界面"""
self.clear_frame()
# 标题栏
title_frame = tk.Frame(self.main_frame, bg='white')
title_frame.pack(fill='x', pady=(10, 20))
back_button = self.create_styled_button(title_frame, "← 返回", self.show_welcome_screen, "#95a5a6", 8)
back_button.pack(side='left')
title_label = tk.Label(
title_frame,
text="📤 文件发送",
font=("Microsoft YaHei", 16, "bold"),
fg="#2c3e50",
bg='white'
)
title_label.pack(side='left', padx=10)
# 输入卡片
input_card = tk.Frame(self.main_frame, bg='#f8f9fa', relief='raised', bd=1, padx=20, pady=20)
input_card.pack(fill='x', pady=(0, 15))
# 密钥输入
key_frame = tk.Frame(input_card, bg='#f8f9fa')
key_frame.pack(fill='x', pady=5)
tk.Label(key_frame, text="🔑 密钥:", font=("Microsoft YaHei", 10), bg='#f8f9fa').pack(side='left')
self.send_key_entry = tk.Entry(key_frame, font=("Microsoft YaHei", 10), width=40, relief='solid', bd=1)
self.send_key_entry.pack(side='left', padx=10)
# 文件选择
file_frame = tk.Frame(input_card, bg='#f8f9fa')
file_frame.pack(fill='x', pady=10)
tk.Label(file_frame, text="📁 文件路径:", font=("Microsoft YaHei", 10), bg='#f8f9fa').pack(side='left')
self.file_path_var = tk.StringVar()
file_entry = tk.Entry(file_frame, textvariable=self.file_path_var, font=("Microsoft YaHei", 10),
width=30, state='readonly', relief='solid', bd=1)
file_entry.pack(side='left', padx=10)
browse_button = self.create_styled_button(file_frame, "浏览文件", self.browse_file, "#8e44ad", 10)
browse_button.pack(side='left')
# 按钮组
button_frame = tk.Frame(self.main_frame, bg='white')
button_frame.pack(pady=15)
self.send_connect_button = self.create_styled_button(button_frame, "🔄 连接", self.start_send_connection, "#27ae60")
self.send_connect_button.pack(side='left', padx=5)
self.send_file_button = self.create_styled_button(button_frame, "🚀 发送文件", self.start_file_send, "#e74c3c")
self.send_file_button.pack(side='left', padx=5)
self.send_file_button.config(state='disabled')
self.send_stop_button = self.create_styled_button(button_frame, "⏹️ 停止", self.stop_send_connection, "#95a5a6")
self.send_stop_button.pack(side='left', padx=5)
self.send_stop_button.config(state='disabled')
# 状态显示
status_frame = tk.Frame(self.main_frame, bg='white')
status_frame.pack(fill='x', pady=5)
self.send_status_label = tk.Label(
status_frame,
text="📊 状态: 等待连接",
font=("Microsoft YaHei", 10),
fg="#7f8c8d",
bg='white'
)
self.send_status_label.pack()
# 输出区域
output_card = tk.Frame(self.main_frame, bg='#f8f9fa', relief='raised', bd=1, padx=15, pady=15)
output_card.pack(fill='both', expand=True, pady=(10, 0))
output_label = tk.Label(output_card, text="📋 发送日志:", font=("Microsoft YaHei", 10), bg='#f8f9fa')
output_label.pack(anchor='w')
self.send_output = scrolledtext.ScrolledText(
output_card,
height=12,
width=80,
font=("Consolas", 9),
state='disabled',
relief='solid',
bd=1,
bg='#ffffff'
)
self.send_output.pack(fill='both', expand=True, pady=(5, 0))
# 初始信息
self.append_send_output("等待输入密钥并选择文件...\n")
self.append_send_output("密钥格式应为: token|sk|psk|sern\n")
# 进程引用
self.send_frpc_process = None
self.send_p2p_process = None
self.is_send_running = False
def show_receive_screen(self):
"""显示接收界面"""
self.clear_frame()
# 标题栏
title_frame = tk.Frame(self.main_frame, bg='white')
title_frame.pack(fill='x', pady=(10, 20))
back_button = self.create_styled_button(title_frame, "← 返回", self.show_welcome_screen, "#95a5a6", 8)
back_button.pack(side='left')
title_label = tk.Label(
title_frame,
text="📥 文件接收",
font=("Microsoft YaHei", 16, "bold"),
fg="#2c3e50",
bg='white'
)
title_label.pack(side='left', padx=10)
# 输入卡片
input_card = tk.Frame(self.main_frame, bg='#f8f9fa', relief='raised', bd=1, padx=20, pady=20)
input_card.pack(fill='x', pady=(0, 15))
# 密钥输入
key_frame = tk.Frame(input_card, bg='#f8f9fa')
key_frame.pack(fill='x', pady=5)
tk.Label(key_frame, text="🔑 密钥:", font=("Microsoft YaHei", 10), bg='#f8f9fa').pack(side='left')
self.receive_key_entry = tk.Entry(key_frame, font=("Microsoft YaHei", 10), width=40, relief='solid', bd=1)
self.receive_key_entry.pack(side='left', padx=10)
# 保存路径选择
path_frame = tk.Frame(input_card, bg='#f8f9fa')
path_frame.pack(fill='x', pady=10)
tk.Label(path_frame, text="💾 保存路径:", font=("Microsoft YaHei", 10), bg='#f8f9fa').pack(side='left')
self.receive_path_var = tk.StringVar()
self.receive_path_var.set(".\\received_files") # 默认路径
path_entry = tk.Entry(path_frame, textvariable=self.receive_path_var, font=("Microsoft YaHei", 10),
width=30, relief='solid', bd=1)
path_entry.pack(side='left', padx=10)
browse_path_button = self.create_styled_button(path_frame, "浏览文件夹", self.browse_receive_path, "#8e44ad", 12)
browse_path_button.pack(side='left')
# 按钮组
button_frame = tk.Frame(self.main_frame, bg='white')
button_frame.pack(pady=15)
self.connect_button = self.create_styled_button(button_frame, "🔄 连接", self.start_frpc_connection, "#27ae60")
self.connect_button.pack(side='left', padx=5)
self.stop_button = self.create_styled_button(button_frame, "⏹️ 停止", self.stop_frpc_connection, "#e74c3c")
self.stop_button.pack(side='left', padx=5)
self.stop_button.config(state='disabled')
# 状态显示
status_frame = tk.Frame(self.main_frame, bg='white')
status_frame.pack(fill='x', pady=5)
self.status_label = tk.Label(
status_frame,
text="📊 状态: 等待连接",
font=("Microsoft YaHei", 10),
fg="#7f8c8d",
bg='white'
)
self.status_label.pack()
# 输出区域
output_card = tk.Frame(self.main_frame, bg='#f8f9fa', relief='raised', bd=1, padx=15, pady=15)
output_card.pack(fill='both', expand=True, pady=(10, 0))
output_label = tk.Label(output_card, text="📋 接收日志:", font=("Microsoft YaHei", 10), bg='#f8f9fa')
output_label.pack(anchor='w')
self.receive_output = scrolledtext.ScrolledText(
output_card,
height=12,
width=80,
font=("Consolas", 9),
state='disabled',
relief='solid',
bd=1,
bg='#ffffff'
)
self.receive_output.pack(fill='both', expand=True, pady=(5, 0))
# 初始信息
self.append_output("等待输入密钥并连接...\n")
self.append_output("密钥格式应为: token|sk|psk|sern\n")
self.append_output(f"文件将保存到: {self.receive_path_var.get()}\n")
# 进程引用
self.frpc_process = None
self.p2p_process = None
self.is_running = False
self.current_stage = "idle"
def browse_receive_path(self):
"""浏览选择接收文件保存路径"""
folder_path = filedialog.askdirectory(
title="选择文件保存目录",
initialdir="."
)
if folder_path:
self.receive_path_var.set(folder_path)
self.append_output(f"✅ 文件将保存到: {folder_path}\n")
def browse_file(self):
"""浏览选择要发送的文件"""
file_path = filedialog.askopenfilename(
title="选择要发送的文件",
filetypes=[
("所有文件", "*.*"),
("文本文件", "*.txt"),
("图片文件", "*.jpg *.png *.gif"),
("视频文件", "*.mp4 *.avi *.mov"),
("文档文件", "*.pdf *.doc *.docx")
]
)
if file_path:
self.file_path_var.set(file_path)
self.append_send_output(f"✅ 已选择文件: {file_path}\n")
def create_send_ini(self, token, sk, sern, bport):
"""创建send.ini配置文件"""
ini_content = f"""[common]
local_ip = 0.0.0.0
server_addr = 47.97.6.201
server_port = 7100
token = {token}
[xtcp_visitor]
type = xtcp
role = visitor
server_name = {sern}
sk = {sk}
bind_ip = 127.0.0.1
bind_port = {bport}
"""
try:
with open('./send.ini', 'w', encoding='utf-8') as f:
f.write(ini_content)
self.append_send_output(f"配置文件 send.ini 创建成功\n")
return True
except Exception as e:
self.append_send_output(f"创建配置文件失败: {e}\n")
return False
def monitor_send_frpc_output(self):
"""监控发送NATCC输出"""
try:
for line in iter(self.send_frpc_process.stdout.readline, ''):
if not self.is_send_running:
break
if line:
self.append_send_output(f"[NATC] {line}")
except:
pass
def monitor_send_p2p_output(self):
"""监控发送P2P输出"""
try:
for line in iter(self.send_p2p_process.stdout.readline, ''):
if not self.is_send_running:
break
if line.strip():
self.append_send_output(f"[P2P] {line}")
# 进程结束后检查退出码
return_code = self.send_p2p_process.wait()
if self.is_send_running:
self.append_send_output(f"[P2P] 文件发送完成,退出码: {return_code}\n")
self.send_file_button.config(state='normal')
except Exception as e:
self.append_send_output(f"[P2P] 输出监控错误: {e}\n")
def execute_send_frpc(self):
"""执行发送NATCC命令"""
try:
self.update_send_status("正在启动NATC客户端...")
self.send_frpc_process = subprocess.Popen(
['.\\gc.exe', '-c', '.\\send.ini'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding='utf-8',
errors='replace',
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
# 启动输出监控线程
output_thread = threading.Thread(target=self.monitor_send_frpc_output, daemon=True)
output_thread.start()
# 等待一段时间让NATCC建立连接
self.append_send_output("[NATC] 等待NATC连接建立...\n")
time.sleep(3)
# 检查NATCC进程是否还在运行
if self.send_frpc_process.poll() is not None:
self.append_send_output("[NATC] NATC客户端意外退出\n")
return
# 如果还在运行,启用发送文件按钮
if self.is_send_running:
self.append_send_output("[NATC] NATC连接已建立,可以发送文件\n")
self.send_file_button.config(state='normal')
self.update_send_status("就绪,可以发送文件")
except Exception as e:
self.append_send_output(f"[NATC] 执行错误: {e}\n")
def execute_send_file(self):
"""执行文件发送"""
try:
self.update_send_status("正在发送文件...")
file_path = self.file_path_var.get()
if not file_path or not os.path.exists(file_path):
self.append_send_output("[错误] 文件路径无效或文件不存在\n")
return
self.send_p2p_process = subprocess.Popen(
[
'.\\python.exe',
'.\\p2pfile.py',
'--mode', 'send',
'--path', file_path,
'--psk', self.send_psk,
'--port', self.bport
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding='gbk',
errors='replace',
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
self.append_send_output(f"[P2P] 开始发送文件: {os.path.basename(file_path)}\n")
# 启动输出监控线程
output_thread = threading.Thread(target=self.monitor_send_p2p_output, daemon=True)
output_thread.start()
except Exception as e:
self.append_send_output(f"[P2P] 执行错误: {e}\n")
def start_send_connection(self):
"""开始发送连接"""
key = self.send_key_entry.get().strip()
if not key:
messagebox.showwarning("输入错误", "请输入密钥")
return
# 解析密钥
if '|' not in key:
messagebox.showwarning("格式错误", "密钥格式应为: token|sk|psk|sern")
return
parts = key.split('|')
if len(parts) < 4:
messagebox.showwarning("格式错误", "密钥格式应为: token|sk|psk|sern")
return
token = parts[0].strip()
sk = parts[1].strip()
psk = parts[2].strip()
sern = parts[3].strip()
bport = parts[4].strip() if len(parts) > 4 else "7001"
self.send_token = token
self.send_sk = sk
self.send_psk = psk
self.send_sern = sern
self.bport = bport
# 创建配置文件
if not self.create_send_ini(token, sk, sern, bport):
return
# 清空输出框
self.send_output.config(state='normal')
self.send_output.delete(1.0, tk.END)
self.send_output.config(state='disabled')
self.append_send_output(f"开始连接流程...\n")
self.append_send_output(f"Token: {token}\n")
self.append_send_output(f"SK: {sk}\n")
self.append_send_output(f"PSK: {psk}\n")
self.append_send_output(f"SERN: {sern}\n")
self.append_send_output(f"BPORT: {bport}\n")
self.append_send_output("-" * 50 + "\n")
# 禁用连接按钮,启用停止按钮
self.send_connect_button.config(state='disabled')
self.send_stop_button.config(state='normal')
# 设置运行标志
self.is_send_running = True
self.update_send_status("启动中...")
# 在新线程中执行NATCC
self.send_process_thread = threading.Thread(target=self.execute_send_frpc, daemon=True)
self.send_process_thread.start()
def start_file_send(self):
"""开始发送文件"""
if not self.file_path_var.get():
messagebox.showwarning("选择错误", "请先选择要发送的文件")
return
# 禁用发送按钮,避免重复点击
self.send_file_button.config(state='disabled')
# 在新线程中执行文件发送
send_thread = threading.Thread(target=self.execute_send_file, daemon=True)
send_thread.start()
def stop_send_connection(self):
"""停止发送连接"""
self.is_send_running = False
self.update_send_status("正在停止...")
# 停止NATCC进程
if self.send_frpc_process and self.send_frpc_process.poll() is None:
try:
self.send_frpc_process.terminate()
self.append_send_output("[NATC] 正在停止NATC客户端...\n")
except:
pass
# 停止P2P进程
if self.send_p2p_process and self.send_p2p_process.poll() is None:
try:
self.send_p2p_process.terminate()
self.append_send_output("[P2P] 正在停止文件发送...\n")
except:
pass
time.sleep(1)
self.send_connect_button.config(state='normal')
self.send_file_button.config(state='disabled')
self.send_stop_button.config(state='disabled')
self.update_send_status("已停止")
self.append_send_output("所有进程已停止\n")
def update_send_status(self, status):
"""更新发送状态标签"""
self.send_status_label.config(text=f"状态: {status}")
def append_send_output(self, message):
"""向发送输出框添加消息"""
self.send_output.config(state='normal')
self.send_output.insert(tk.END, message)
self.send_output.see(tk.END)
self.send_output.config(state='disabled')
def create_service_ini(self, token, sk, sern, bport):
"""创建service.ini配置文件"""
ini_content = f"""[common]
server_addr = 47.97.6.201
server_port = 7100
token = {token}
[{sern}]
type = xtcp
sk = {sk}
local_ip = 127.0.0.1
local_port = {bport}
"""
try:
with open('./service.ini', 'w', encoding='utf-8') as f:
f.write(ini_content)
self.append_output(f"配置文件 service.ini 创建成功\n")
return True
except Exception as e:
self.append_output(f"创建配置文件失败: {e}\n")
return False
def execute_frpc(self):
"""执行frpc命令"""
try:
self.current_stage = "frpc"
self.update_status("正在启动NATC客户端...")
self.frpc_process = subprocess.Popen(
['.\\gc.exe', '-c', '.\\service.ini'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding='utf-8',
errors='replace',
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
# 启动输出监控线程
output_thread = threading.Thread(target=self.monitor_frpc_output, daemon=True)
output_thread.start()
# 等待一段时间让NATCC建立连接
self.append_output("[NATC] 等待NATC连接建立...\n")
time.sleep(3) # 等待3秒让NATCC建立连接
# 检查NATCC进程是否还在运行
if self.frpc_process.poll() is not None:
self.append_output("[NATC] NATC客户端意外退出\n")
return
# 如果还在运行,启动P2P
if self.is_running:
self.append_output("[NATC] NATC连接已建立,启动P2P接收器...\n")
self.execute_p2p_receiver()
except Exception as e:
self.append_output(f"[NATC] 执行错误: {e}\n")
def monitor_frpc_output(self):
"""监控NATCC输出"""
try:
for line in iter(self.frpc_process.stdout.readline, ''):
if not self.is_running:
break
if line:
self.append_output(f"[NATC] {line}")
except:
pass
def monitor_p2p_output(self):
"""监控P2P输出并检测进程结束"""
try:
for line in iter(self.p2p_process.stdout.readline, ''):
if not self.is_running:
break
if line.strip():
self.append_output(f"[P2P] {line}")
# 进程结束后检查退出码
return_code = self.p2p_process.wait()
if self.is_running:
self.append_output(f"[P2P] P2P接收器已停止,退出码: {return_code}\n")
except Exception as e:
self.append_output(f"[P2P] 输出监控错误: {e}\n")
def execute_p2p_receiver(self):
"""执行P2P文件接收器"""
try:
self.current_stage = "p2p"
self.update_status("正在启动P2P文件接收...")
# 获取用户选择的保存路径
save_path = self.receive_path_var.get().strip()
if not save_path:
save_path = ".\\received_files" # 默认路径
# 创建目录(如果不存在)
os.makedirs(save_path, exist_ok=True)
self.p2p_process = subprocess.Popen(
[
'.\\python.exe',
'.\\p2pfile.py',
'--mode', 'recv',
'--psk', self.current_psk,
'--outdir', save_path,
'--port', self.bport
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding='gbk',
errors='replace',
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
self.append_output("[P2P] 启动P2P文件接收器...\n")
self.append_output(f"[P2P] 使用PSK: {self.current_psk}\n")
self.append_output(f"[P2P] 文件保存路径: {save_path}\n")
# 启动输出监控线程
output_thread = threading.Thread(target=self.monitor_p2p_output, daemon=True)
output_thread.start()
# 检查进程是否立即失败
time.sleep(1)
if self.p2p_process.poll() is not None:
self.append_output("[P2P] P2P接收器启动失败\n")
except Exception as e:
self.append_output(f"[P2P] 执行错误: {e}\n")
def start_frpc_connection(self):
"""开始NATC连接和P2P接收"""
key = self.receive_key_entry.get().strip()
if not key:
messagebox.showwarning("输入错误", "请输入密钥")
return
# 解析密钥
if '|' not in key:
messagebox.showwarning("格式错误", "密钥格式应为: token|sk|psk|sern")
return
parts = key.split('|')
if len(parts) < 4:
messagebox.showwarning("格式错误", "密钥格式应为: token|sk|psk|sern")
return
token = parts[0].strip()
sk = parts[1].strip()
psk = parts[2].strip()
sern = parts[3].strip()
# 修改: 当缺少bport时,默认使用7001
bport = parts[4].strip() if len(parts) > 4 else "6000"
self.current_token = token
self.current_sk = sk
self.current_psk = psk
self.current_sern = sern
self.bport = bport
# 获取保存路径并显示
save_path = self.receive_path_var.get()
self.append_output(f"📁 保存路径: {save_path}\n")
# 创建配置文件
if not self.create_service_ini(token, sk, sern, bport):
return
# 清空输出框
self.receive_output.config(state='normal')
self.receive_output.delete(1.0, tk.END)
self.receive_output.config(state='disabled')
self.append_output(f"开始连接流程...\n")
self.append_output(f"Token: {token}\n")
self.append_output(f"SK: {sk}\n")
self.append_output(f"PSK: {psk}\n")
self.append_output(f"SERN: {sern}\n")
self.append_output(f"保存路径: {save_path}\n")
self.append_output(f"port: {bport}\n")
self.append_output("-" * 50 + "\n")
# 禁用连接按钮,启用停止按钮
self.connect_button.config(state='disabled')
self.stop_button.config(state='normal')
# 设置运行标志
self.is_running = True
self.update_status("启动中...")
# 在新线程中执行
self.process_thread = threading.Thread(target=self.execute_frpc, daemon=True)
self.process_thread.start()
def stop_frpc_connection(self):
"""停止所有进程"""
self.is_running = False
self.update_status("正在停止...")
# 停止NATCC进程
if self.frpc_process and self.frpc_process.poll() is None:
try:
self.frpc_process.terminate()
self.append_output("[NATC] 正在停止NATC客户端...\n")
except:
pass
# 停止P2P进程
if self.p2p_process and self.p2p_process.poll() is None:
try:
self.p2p_process.terminate()
self.append_output("[P2P] 正在停止P2P接收器...\n")
except:
pass
time.sleep(1) # 给进程一些时间结束
self.connect_button.config(state='normal')
self.stop_button.config(state='disabled')
self.update_status("已停止")
self.append_output("所有进程已停止\n")
def update_status(self, status):
"""更新状态标签"""
self.status_label.config(text=f"状态: {status}")
def append_output(self, message):
"""向输出框添加消息"""
self.receive_output.config(state='normal')
self.receive_output.insert(tk.END, message)
self.receive_output.see(tk.END) # 自动滚动到底部
self.receive_output.config(state='disabled')
# 创建主窗口并运行程序
if __name__ == "__main__":
root = tk.Tk()
app = FileTransferApp(root)
root.mainloop()