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.
 
 
 
 
 
 

1615 lines
61 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.page_states = {
'welcome': {},
'send': {
'is_running': False,
'frpc_process': None,
'p2p_process': None,
'key_entry_text': '',
'file_path': '',
'output_content': ''
},
'receive': {
'is_running': False,
'frpc_process': None,
'p2p_process': None,
'key_entry_text': '',
'save_path': '.\\received_files',
'output_content': ''
},
'cloud': {
'is_running': False,
'cloud_process': None,
'output_content': ''
}
}
self.current_page = None
# 设置样式
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 save_current_page_state(self):
"""保存当前页面的状态"""
if self.current_page == 'send':
self.page_states['send']['key_entry_text'] = self.send_key_entry.get()
self.page_states['send']['file_path'] = self.file_path_var.get()
self.page_states['send']['output_content'] = self.send_output.get(1.0, tk.END)
elif self.current_page == 'receive':
self.page_states['receive']['key_entry_text'] = self.receive_key_entry.get()
self.page_states['receive']['save_path'] = self.receive_path_var.get()
self.page_states['receive']['output_content'] = self.receive_output.get(1.0, tk.END)
elif self.current_page == 'cloud':
self.page_states['cloud']['output_content'] = self.cloud_output.get(1.0, tk.END)
def restore_page_state(self, page_name):
"""恢复指定页面的状态"""
state = self.page_states[page_name]
if page_name == 'send':
self.send_key_entry.delete(0, tk.END)
self.send_key_entry.insert(0, state['key_entry_text'])
self.file_path_var.set(state['file_path'])
self.send_output.config(state='normal')
self.send_output.delete(1.0, tk.END)
self.send_output.insert(1.0, state['output_content'])
self.send_output.config(state='disabled')
# 恢复按钮状态
if state['is_running']:
self.send_connect_button.config(state='disabled')
self.send_stop_button.config(state='normal')
self.send_file_button.config(state='normal' if state['file_path'] else 'disabled')
else:
self.send_connect_button.config(state='normal')
self.send_stop_button.config(state='disabled')
self.send_file_button.config(state='disabled')
self.update_send_status("运行中" if state['is_running'] else "等待连接")
elif page_name == 'receive':
self.receive_key_entry.delete(0, tk.END)
self.receive_key_entry.insert(0, state['key_entry_text'])
self.receive_path_var.set(state['save_path'])
self.receive_output.config(state='normal')
self.receive_output.delete(1.0, tk.END)
self.receive_output.insert(1.0, state['output_content'])
self.receive_output.config(state='disabled')
# 恢复按钮状态
if state['is_running']:
self.connect_button.config(state='disabled')
self.stop_button.config(state='normal')
else:
self.connect_button.config(state='normal')
self.stop_button.config(state='disabled')
self.update_status("运行中" if state['is_running'] else "等待连接")
elif page_name == 'cloud':
self.cloud_output.config(state='normal')
self.cloud_output.delete(1.0, tk.END)
self.cloud_output.insert(1.0, state['output_content'])
self.cloud_output.config(state='disabled')
# 恢复按钮状态
if state['is_running']:
self.cloud_start_button.config(state='disabled')
self.cloud_stop_button.config(state='normal')
self.cloud_status_label.config(text="📊 状态: 加速服务运行中", fg="#27ae60")
else:
self.cloud_start_button.config(state='normal')
self.cloud_stop_button.config(state='disabled')
self.cloud_status_label.config(text="📊 状态: 等待启动加速服务", fg="#7f8c8d")
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_confirm_dialog(self, stop_command, success_callback):
"""显示确认对话框"""
def on_confirm():
# 执行停止命令
stop_command()
# 关闭对话框
confirm_dialog.destroy()
# 执行成功回调
success_callback()
def on_cancel():
confirm_dialog.destroy()
# 创建确认对话框
confirm_dialog = tk.Toplevel(self.root)
confirm_dialog.title("确认离开")
confirm_dialog.geometry("400x200")
confirm_dialog.configure(bg='white')
confirm_dialog.resizable(False, False)
confirm_dialog.transient(self.root) # 设置为主窗口的临时窗口
confirm_dialog.grab_set() # 模态对话框
# 居中显示
confirm_dialog.update_idletasks()
x = (self.root.winfo_screenwidth() - confirm_dialog.winfo_width()) // 2
y = (self.root.winfo_screenheight() - confirm_dialog.winfo_height()) // 2
confirm_dialog.geometry(f"+{x}+{y}")
# 图标和提示文字
icon_label = tk.Label(confirm_dialog, text="⚠️", font=("Arial", 24), bg='white')
icon_label.pack(pady=(20, 10))
message_label = tk.Label(
confirm_dialog,
text="你正离开当前界面,会停止运行当前功能",
font=("Microsoft YaHei", 12),
fg="#2c3e50",
bg='white',
wraplength=350
)
message_label.pack(pady=(0, 20))
# 按钮框架
button_frame = tk.Frame(confirm_dialog, bg='white')
button_frame.pack(pady=10)
# 取消按钮
cancel_button = tk.Button(
button_frame,
text="取消",
command=on_cancel,
font=("Microsoft YaHei", 11),
bg="#95a5a6",
fg="white",
width=10,
relief='flat'
)
cancel_button.pack(side='left', padx=10)
# 确认按钮
confirm_button = tk.Button(
button_frame,
text="确认",
command=on_confirm,
font=("Microsoft YaHei", 11),
bg="#e74c3c",
fg="white",
width=10,
relief='flat'
)
confirm_button.pack(side='left', padx=10)
# 绑定回车和ESC键
confirm_dialog.bind('<Return>', lambda e: on_confirm())
confirm_dialog.bind('<Escape>', lambda e: on_cancel())
confirm_button.focus_set()
def show_welcome_screen(self):
"""显示欢迎界面"""
if self.current_page:
# 根据当前页面类型决定停止命令
if self.current_page == 'send' and self.page_states['send']['is_running']:
self.show_confirm_dialog(self.stop_send_connection, self._show_welcome_screen)
return
elif self.current_page == 'receive' and self.page_states['receive']['is_running']:
self.show_confirm_dialog(self.stop_frpc_connection, self._show_welcome_screen)
return
elif self.current_page == 'cloud' and self.page_states['cloud']['is_running']:
self.show_confirm_dialog(self.stop_cloud_accel, self._show_welcome_screen)
return
# 如果没有运行中的功能,直接显示欢迎界面
self._show_welcome_screen()
def _show_welcome_screen(self):
"""显示欢迎界面"""
if self.current_page:
self.save_current_page_state()
self.clear_frame()
self.current_page = 'welcome'
# 顶部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()
# 提示语框架
tip_frame = tk.Frame(self.main_frame, bg='white')
tip_frame.pack(pady=(10, 30))
tip_label = tk.Label(
tip_frame,
text="💡 提示:可通过多次打开软件,分别进行发送、接收和加速操作",
font=("Microsoft YaHei", 11, "bold"),
fg="#e67e22", # 使用橙色突出显示
bg='white',
wraplength=600 # 限制宽度,自动换行
)
tip_label.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", 12),
fg="#bdc3c7",
bg='white'
)
footer_label.pack()
def show_cloud_accel_screen(self):
"""显示网盘加速界面"""
if self.current_page and self.current_page != 'cloud':
# 检查当前页面是否有运行中的功能
if self.current_page == 'send' and self.page_states['send']['is_running']:
self.show_confirm_dialog(self.stop_send_connection, self._show_cloud_accel_screen)
return
elif self.current_page == 'receive' and self.page_states['receive']['is_running']:
self.show_confirm_dialog(self.stop_frpc_connection, self._show_cloud_accel_screen)
return
# 如果没有运行中的功能,直接显示网盘加速界面
self._show_cloud_accel_screen()
def _show_cloud_accel_screen(self):
"""显示网盘加速界面"""
if self.current_page:
self.save_current_page_state()
self.clear_frame()
self.current_page = 'cloud'
# 标题栏
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
# 恢复状态
if hasattr(self, 'cloud_output'):
self.restore_page_state('cloud')
# 修改所有页面切换方法,使用lambda包装
def setup_navigation(self):
"""设置页面导航"""
# 在欢迎界面中
send_button = tk.Button(..., command=lambda: self.show_send_screen())
receive_button = tk.Button(..., command=lambda: self.show_receive_screen())
cloud_button = tk.Button(..., command=lambda: self.show_cloud_accel_screen())
# 在各个功能界面中
back_button = tk.Button(..., command=lambda: self.show_welcome_screen())
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):
"""启动网盘加速服务"""
bport = 8089
# 检查6000端口是否被占用
occupying_pids = self.get_processes_using_port(bport)
if occupying_pids:
self.append_send_output(f"[警告] {bport}端口被以下进程占用:\n")
for pid, process_name in occupying_pids:
self.append_send_output(f" - PID: {pid}, 进程: {process_name}\n")
self.append_send_output("[提示] 请手动关闭这些进程或更改端口配置后再试\n")
return
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.page_states['cloud']['cloud_process'] = self.cloud_process
# 更新状态
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()
# 更新状态
self.page_states['cloud']['is_running'] = True
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")
# 更新状态
self.page_states['cloud']['is_running'] = False
def append_cloud_output(self, message):
"""向网盘加速输出框添加消息"""
self.cloud_output.config(state='normal')
self.cloud_output.insert(tk.END, message)
self.cloud_output.see(tk.END)
self.cloud_output.config(state='disabled')
# 更新状态存储
self.page_states['cloud']['output_content'] = self.cloud_output.get(1.0, tk.END)
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):
"""显示发送界面"""
if self.current_page and self.current_page != 'send':
# 检查当前页面是否有运行中的功能
if self.current_page == 'receive' and self.page_states['receive']['is_running']:
self.show_confirm_dialog(self.stop_frpc_connection, self._show_send_screen)
return
elif self.current_page == 'cloud' and self.page_states['cloud']['is_running']:
self.show_confirm_dialog(self.stop_cloud_accel, self._show_send_screen)
return
# 如果没有运行中的功能,直接显示发送界面
self._show_send_screen()
def _show_send_screen(self):
"""显示发送界面"""
if self.current_page:
self.save_current_page_state()
self.clear_frame()
self.current_page = 'send'
# 标题栏
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
# 初始化或恢复状态
if not hasattr(self, 'send_key_entry'):
# 第一次创建界面
self.send_key_entry = tk.Entry(key_frame, font=("Microsoft YaHei", 10), width=40, relief='solid', bd=1)
self.file_path_var = tk.StringVar()
# ... 其他控件初始化
else:
# 恢复状态
self.restore_page_state('send')
def show_receive_screen(self):
"""显示接收界面"""
if self.current_page and self.current_page != 'receive':
# 检查当前页面是否有运行中的功能
if self.current_page == 'send' and self.page_states['send']['is_running']:
self.show_confirm_dialog(self.stop_send_connection, self._show_receive_screen)
return
elif self.current_page == 'cloud' and self.page_states['cloud']['is_running']:
self.show_confirm_dialog(self.stop_cloud_accel, self._show_receive_screen)
return
# 如果没有运行中的功能,直接显示接收界面
self._show_receive_screen()
def _show_receive_screen(self):
"""显示接收界面"""
if self.current_page:
self.save_current_page_state()
self.clear_frame()
self.current_page = 'receive'
# 标题栏
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"
# 初始化或恢复状态
if not hasattr(self, 'receive_key_entry'):
# 第一次创建界面
self.receive_key_entry = tk.Entry(key_frame, font=("Microsoft YaHei", 10), width=40, relief='solid', bd=1)
self.receive_path_var = tk.StringVar(value=".\\received_files")
# ... 其他控件初始化
else:
# 恢复状态
self.restore_page_state('receive')
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()
end_time = time.time()
end_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))
# 计算耗时
duration = end_time - self.send_start_time
duration_str = self.format_duration(duration)
if self.is_send_running:
if return_code == 0:
self.append_send_output(f"[时间] 文件发送完成: {end_time_str}\n")
self.append_send_output(f"[统计] 总耗时: {duration_str}\n")
self.append_send_output("✅ 文件发送成功完成!\n")
else:
self.append_send_output(f"[时间] 文件发送异常结束: {end_time_str}\n")
self.append_send_output(f"[统计] 运行时间: {duration_str}\n")
self.append_send_output(f"❌ 文件发送失败,退出码: {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 # 不创建窗口
)
self.page_states['send']['p2p_process'] = self.send_p2p_process
# 启动输出监控线程
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_start_time = time.time()
start_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.send_start_time))
self.append_send_output(f"[时间] 文件发送开始: {start_time_str}\n")
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = 0
file_path = self.file_path_var.get()
file_size = os.path.getsize(file_path)
file_name = os.path.basename(file_path)
self.append_send_output(f"[文件] 名称: {file_name}\n")
self.append_send_output(f"[文件] 大小: {self.format_file_size(file_size)}\n")
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
# 检查7001端口是否被占用
occupying_pids = self.get_processes_using_port(bport)
if occupying_pids:
self.append_send_output(f"[警告] {bport}端口被以下进程占用:\n")
for pid, process_name in occupying_pids:
self.append_send_output(f" - PID: {pid}, 进程: {process_name}\n")
self.append_send_output("[提示] 请手动关闭这些进程或更改端口配置后再试\n")
return
# 创建配置文件
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()
# 更新状态
self.page_states['send']['is_running'] = True
self.page_states['send']['key_entry_text'] = key
self.page_states['send']['file_path'] = self.file_path_var.get()
def get_processes_using_port(self, port):
"""获取占用指定端口的进程信息"""
try:
if os.name == 'nt': # Windows系统
return self._get_processes_windows(port)
else: # Linux/Mac系统
self.append_send_output(f"linux系统")
return []
except Exception as e:
self.append_send_output(f"[错误] 获取端口信息时出错: {e}\n")
return []
def _get_processes_windows(self, port):
"""Windows系统下获取占用端口的进程信息"""
processes = []
try:
# 方法1: 使用netstat命令
result = subprocess.run(
['netstat', '-ano', '-p', 'tcp'],
capture_output=True, text=True, encoding='gbk',creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
lines = result.stdout.split('\n')
for line in lines:
if f':{port}' in line and 'LISTENING' in line:
parts = line.split()
if len(parts) >= 5:
pid = parts[-1].strip()
process_name = self._get_process_name_windows(pid)
processes.append((pid, process_name))
# 方法2: 使用PowerShell备用
if not processes:
processes = self._get_processes_windows_ps(port)
except Exception as e:
self.append_send_output(f"[错误] Windows端口检测失败: {e}\n")
return processes
def _get_processes_windows_ps(self, port):
"""Windows使用PowerShell获取进程信息"""
processes = []
try:
ps_command = f"Get-NetTCPConnection -LocalPort {port} | Select-Object OwningProcess, @{{Name='ProcessName'; Expression={{ (Get-Process -Id $_.OwningProcess).Name }} }}"
result = subprocess.run(
['powershell', '-Command', ps_command],
capture_output=True, text=True, timeout=10,creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
if result.returncode == 0:
lines = result.stdout.strip().split('\n')
for line in lines:
if 'OwningProcess' in line and 'ProcessName' in line:
continue # 跳过标题行
parts = line.split()
if len(parts) >= 2:
pid = parts[0].strip()
process_name = parts[1].strip() if len(parts) > 1 else "未知进程"
processes.append((pid, process_name))
except Exception as e:
self.append_send_output(f"[错误] PowerShell检测失败: {e}\n")
return processes
def _get_process_name_windows(self, pid):
"""Windows下根据PID获取进程名称"""
try:
result = subprocess.run(
['tasklist', '/fi', f'pid eq {pid}', '/fo', 'csv', '/nh'],
capture_output=True, text=True, encoding='gbk',creationflags=subprocess.CREATE_NO_WINDOW # 不创建窗口
)
if result.returncode == 0 and result.stdout.strip():
# CSV格式: "进程名","PID","会话名","会话#","内存使用"
parts = result.stdout.strip().split('","')
if len(parts) >= 1:
process_name = parts[0].replace('"', '')
return process_name
except:
pass
return "未知进程"
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")
# 更新状态
self.page_states['send']['is_running'] = False
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')
# 更新状态存储
self.page_states['send']['output_content'] = self.send_output.get(1.0, tk.END)
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
# 在所有的 subprocess.Popen 调用中添加 CREATE_NO_WINDOW 标志
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 # 不创建窗口
)
self.page_states['receive']['frpc_process'] = self.frpc_process
# 启动输出监控线程
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()
end_time = time.time()
end_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))
# 计算耗时
duration = end_time - self.receive_start_time
duration_str = self.format_duration(duration)
if self.is_running:
if return_code == 0:
self.append_output(f"[时间] 文件接收完成: {end_time_str}\n")
self.append_output(f"[统计] 总耗时: {duration_str}\n")
self.append_output("✅ 文件接收成功完成!\n")
else:
self.append_output(f"[时间] 文件接收异常结束: {end_time_str}\n")
self.append_output(f"[统计] 运行时间: {duration_str}\n")
self.append_output(f"❌ 文件接收失败,退出码: {return_code}\n")
except Exception as e:
self.append_output(f"[P2P] 输出监控错误: {e}\n")
def format_file_size(self, size_bytes):
"""格式化文件大小"""
if size_bytes == 0:
return "0B"
size_names = ["B", "KB", "MB", "GB", "TB"]
i = 0
size = size_bytes
while size >= 1024 and i < len(size_names) - 1:
size /= 1024
i += 1
return f"{size:.2f} {size_names[i]}"
def format_duration(self, seconds):
"""格式化时间间隔"""
if seconds < 60:
return f"{seconds:.1f}"
elif seconds < 3600:
minutes = seconds // 60
seconds = seconds % 60
return f"{int(minutes)}{int(seconds)}"
else:
hours = seconds // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
return f"{int(hours)}{int(minutes)}{int(seconds)}"
def execute_p2p_receiver(self):
"""执行P2P文件接收器"""
try:
self.current_stage = "p2p"
self.update_status("正在启动P2P文件接收...")
# 记录开始时间
self.receive_start_time = time.time()
start_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.receive_start_time))
self.append_output(f"[时间] 文件接收开始: {start_time_str}\n")
# 获取用户选择的保存路径
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.page_states['receive']['p2p_process'] = self.p2p_process
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
# 检查6000端口是否被占用
occupying_pids = self.get_processes_using_port(bport)
if occupying_pids:
self.append_send_output(f"[警告] {bport}端口被以下进程占用:\n")
for pid, process_name in occupying_pids:
self.append_send_output(f" - PID: {pid}, 进程: {process_name}\n")
self.append_send_output("[提示] 请手动关闭这些进程或更改端口配置后再试\n")
return
# 获取保存路径并显示
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()
# 更新状态
self.page_states['receive']['is_running'] = True
self.page_states['receive']['key_entry_text'] = key
self.page_states['receive']['save_path'] = self.receive_path_var.get()
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")
self.page_states['receive']['is_running'] = False
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')
# 更新状态存储
self.page_states['receive']['output_content'] = self.receive_output.get(1.0, tk.END)
# 创建主窗口并运行程序
if __name__ == "__main__":
root = tk.Tk()
app = FileTransferApp(root)
root.mainloop()