接上,使用繁體中文,在clinet端的程式,請加上"方法 2: 解析 udp-receiver.exe 的輸出",補獲client端的標準輸出,如進度資訊(如傳送速度、傳送進度等)回報給伺服端並在檔案傳輸完成後,使用 檔案校驗碼(如 MD5 或 SHA256) 來驗證檔案的完整性。當 client 端完成檔案接收後,計算接收檔案的校驗碼,並將校驗碼傳送回 server 端,server 再進行比對,以確定檔案是否正確傳輸,執行時希望在背景執行,不要有終端機的畫面出現,
,而伺服端在傳送檔案的同時,在UI的界面上希望能呈現client端的標準輸出,可以有一個欄位呈現檔案傳送的狀態,此狀態包含檔案名稱、檔案大小、傳輸速度、傳輸時間、檔案校驗碼,並在檔案傳輸完成時,alert一個提示訊息通知伺服端使用者已完成檔案傳送,請同時修正伺服端及client端的程式,謝謝
伺服端
標題藍底,白字
# 建立標題
self.label_title = tk.Label(root, text="UDP派送檔案", bg="deepskyblue", fg="white", font=("Arial", 18))
self.label_title.pack(fill=tk.X)
# 建立表格標題與資料置中
self.tree = ttk.Treeview(root, columns=("IP", "MAC", "Name", "Status"), show='headings')
self.tree.heading("IP", text="IP 位置", anchor="center")
self.tree.heading("MAC", text="MAC 位置", anchor="center")
self.tree.heading("Name", text="電腦名稱", anchor="center")
self.tree.heading("Status", text="狀態", anchor="center")
# 設定每個欄位的資料置中
self.tree.column("IP", anchor="center")
self.tree.column("MAC", anchor="center")
self.tree.column("Name", anchor="center")
self.tree.column("Status", anchor="center")
self.tree.pack(fill=tk.BOTH, expand=True)
# 左邊格 - 跑馬燈效果,文字顏色改為navy
self.marquee_text = "感謝ChatGPT 感謝UDPcast "
self.marquee_label = tk.Label(self.footer_frame, text=self.marquee_text, font=("Arial", 12), fg="navy")
self.marquee_label.pack(side=tk.LEFT, padx=10)
# 右邊格 - 固定文字,文字顏色改為navy
self.fixed_label = tk.Label(self.footer_frame, text="製作者:WCS 日期:202410.01", font=("Arial", 12), fg="navy")
self.fixed_label.pack(side=tk.RIGHT, padx=10)
# 啟動跑馬燈
self.move_text()
def move_text(self):
# 跑馬燈效果,將字串每次往左移動一個字符
self.marquee_text = self.marquee_text[1:] + self.marquee_text[0]
self.marquee_label.config(text=self.marquee_text)
self.root.after(200, self.move_text) # 每200毫秒移動一次
client端
要讓 server 端知道 client 端在使用 udp-receiver.exe 接收大檔案的進度,可以透過以下幾種方式實現進度回報:
在 client 端每接收一部分檔案時,主動將接收的進度資訊透過 UDP 發送回 server,讓 server 了解檔案的傳輸進度。
這種方式可以根據接收的檔案大小和進度比例來回報。你可以讓 client 每接收到一定量的資料後,發送進度到 server。
實作步驟:
修改 client 端: 在 client 端監控檔案接收進度,並透過 UDP 回報給 server。
python
複製程式碼
import os
import subprocess
import socket
def receive_file_via_udp(file_path):
file_size = 0
if os.path.exists(file_path):
file_size = os.path.getsize(file_path)
# 假設檔案接收過程中會定期刷新檔案,這裡以輪詢方式模擬進度
received_size = 0
while received_size < file_size:
# 模擬接收的資料,這裡的接收邏輯依據實際情況更新
received_size += 1024 * 1024 # 模擬每次接收 1MB 的數據
progress = (received_size / file_size) * 100
# 回報傳輸進度
report_progress_to_server(progress)
# 模擬等待
time.sleep(1)
# 完成接收後,執行 udp-receiver.exe
subprocess.run(['udp-receiver.exe', '--file', file_path])
def report_progress_to_server(progress):
server_ip = '伺服器的IP地址'
server_port = 8501 # 設定伺服器端接收進度回報的埠號
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = f"進度: {progress:.2f}%"
client_socket.sendto(message.encode(), (server_ip, server_port))
client_socket.close()
# 模擬檔案接收功能
receive_file_via_udp('received_file')
修改 server 端: 在 server 端監聽進度更新,並顯示接收到的進度資訊。
python
複製程式碼
import socket
def listen_for_progress_updates():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("", 8501)) # 使用 client 相同的埠號
while True:
data, addr = server_socket.recvfrom(1024)
print(f"來自 {addr} 的進度回報:{data.decode()}")
# 啟動伺服器端進度更新監聽
listen_for_progress_updates()
在 client 端直接解析 udp-receiver.exe 執行時的輸出信息,並將這些進度資訊回報給 server。udp-receiver.exe 的輸出通常包含進度資訊,可以通過 subprocess 捕獲並處理這些輸出。
實作步驟:
修改 client 端: 使用 subprocess.Popen 捕獲 udp-receiver.exe 的標準輸出,並解析進度資訊後回報給 server。
python
複製程式碼
import subprocess
import socket
import re
def receive_file_via_udp():
server_ip = '伺服器的IP地址'
server_port = 8501
process = subprocess.Popen(['udp-receiver.exe', '--file', 'received_file'], stdout=subprocess.PIPE, text=True)
for line in process.stdout:
# 假設 udp-receiver 的進度輸出格式為類似 "XX% complete"
match = re.search(r'(\d+)%', line)
if match:
progress = match.group(1)
report_progress_to_server(progress, server_ip, server_port)
def report_progress_to_server(progress, server_ip, server_port):
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = f"進度: {progress}%"
client_socket.sendto(message.encode(), (server_ip, server_port))
client_socket.close()
# 啟動檔案接收並回報進度
receive_file_via_udp()
此方法適合不需要即時進度的情況。當 client 完成檔案接收後,發送一個完成訊息給 server,讓 server 知道傳輸已經結束。
python
複製程式碼
import subprocess
import socket
def receive_file_via_udp():
process = subprocess.run(['udp-receiver.exe', '--file', 'received_file'], capture_output=True)
if process.returncode == 0:
print("檔案接收完成")
send_completion_status_to_server("接收完成")
else:
print("檔案接收失敗")
send_completion_status_to_server("接收失敗")
def send_completion_status_to_server(status_message):
server_ip = '伺服器的IP地址'
server_port = 8501
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.sendto(status_message.encode(), (server_ip, server_port))
client_socket.close()
receive_file_via_udp()
此方法可應用於定期檢查接收的檔案大小,根據實際大小計算進度並回報給 server。這種方式可以應對 udp-receiver.exe 不能提供進度輸出的情況。
實作步驟:
監控檔案的當前大小。
根據預期檔案大小,回報進度。
python
複製程式碼
import os
import time
import socket
def monitor_file_progress(file_path, total_size):
server_ip = '伺服器的IP地址'
server_port = 8501
while True:
if os.path.exists(file_path):
current_size = os.path.getsize(file_path)
progress = (current_size / total_size) * 100
report_progress_to_server(progress, server_ip, server_port)
time.sleep(1)
def report_progress_to_server(progress, server_ip, server_port):
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = f"進度: {progress:.2f}%"
client_socket.sendto(message.encode(), (server_ip, server_port))
client_socket.close()
# 假設檔案總大小為 100MB
monitor_file_progress('received_file', 100 * 1024 * 1024)
這些方法都可以有效地讓 server 端知道 client 端接收檔案的進度。依據你的需求選擇合適的方式進行實作。
要知道 client 端在使用 udp-receiver.exe 完成檔案接收,可以使用以下幾種方式:
udp-receiver.exe 完成檔案接收後會自動退出,當程序結束時,你可以檢查它的結束代碼,這樣可以判斷接收是否成功完成。在 client 端,你可以監控 udp-receiver.exe 的執行狀態,一旦程序結束,將其回報給 server。
範例: 在 client 端,監控 udp-receiver.exe 程序的結束狀態,並回傳結果給 server。
python
複製程式碼
import subprocess
import socket
def receive_file_via_udp():
# 執行 udp-receiver.exe 並等待接收檔案完成
process = subprocess.run(['udp-receiver.exe', '--file', 'received_file'], capture_output=True)
# 當接收完成後,檢查程序是否成功結束
if process.returncode == 0:
print("檔案接收完成")
send_completion_status_to_server(True)
else:
print("檔案接收失敗")
send_completion_status_to_server(False)
def send_completion_status_to_server(success):
# 這裡可以將檔案接收成功或失敗的狀態回報給伺服端
server_ip = '伺服器的IP地址'
server_port = 8501 # 設定伺服器端接收完成訊息的埠號
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = "接收完成" if success else "接收失敗"
client_socket.sendto(message.encode(), (server_ip, server_port))
client_socket.close()
# 啟動接收檔案的功能
receive_file_via_udp()
在 client 端運行此程式,當 udp-receiver.exe 完成檔案接收時,會將接收完成的狀態回報給 server。
你可以在 client 端每當 udp-receiver.exe 完成接收時,使用 UDP 向 server 端傳送訊息,表示已完成檔案接收。
範例:
server 端建立一個監聽 completion status 的 socket。
python
複製程式碼
import socket
def listen_for_completion_status():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("", 8501)) # 使用與 client 相同的埠號
while True:
data, addr = server_socket.recvfrom(1024)
print(f"來自 {addr} 的訊息:{data.decode()}")
# 啟動伺服器端監聽程序
listen_for_completion_status()
在 client 端每次完成接收後,向伺服器傳送訊息,告知檔案已成功接收。
除了使用回報機制,也可以在傳輸後,使用 檔案校驗碼(如 MD5 或 SHA256) 來驗證檔案的完整性。當 client 端完成檔案接收後,計算接收檔案的校驗碼,並將校驗碼傳送回 server 端,server 再進行比對,以確定檔案是否正確傳輸。
步驟:
server 端傳送檔案前,先計算出檔案的校驗碼。
client 端完成接收後,計算接收到的檔案的校驗碼,並將結果回報給 server。
server 端比對校驗碼,確認檔案傳輸是否成功。
這樣可以保證檔案接收不僅完成,且檔案內容正確無誤。
你可以選擇任意一種方法,依需求進行實作。
要將來自伺服器端的進度更新顯示在 Python 的 UI 界面上,您可以使用像是 Tkinter 這樣的 GUI 框架。以下是一個簡單的範例,展示如何將接收到的進度更新顯示在 Tkinter 的標籤中。
python
複製程式碼
import socket
import threading
import tkinter as tk
def listen_for_progress_updates(label):
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("", 8501)) # 使用 client 相同的埠號
while True:
data, addr = server_socket.recvfrom(1024)
message = f"來自 {addr} 的進度回報:{data.decode()}"
# 更新 UI,必須在主線程中執行
label.after(0, lambda m=message: label.config(text=m))
def start_server(label):
# 使用線程來執行伺服器監聽,避免阻塞 UI
threading.Thread(target=listen_for_progress_updates, args=(label,), daemon=True).start()
# 建立 UI 界面
root = tk.Tk()
root.title("進度更新監聽器")
label = tk.Label(root, text="等待進度更新...", font=("Arial", 14))
label.pack(pady=20)
start_server(label)
root.mainloop()
Tkinter 初始化:這段程式碼首先建立了一個簡單的 Tkinter 窗口,並顯示一個標籤來顯示進度更新。
進度更新的監聽:在 listen_for_progress_updates 函數中,伺服器持續監聽來自客戶端的 UDP 數據。
更新 UI:當接收到數據後,通過 label.after(0, ...) 來確保 UI 更新在主線程中進行,這樣可以避免因直接更新 UI 而導致的問題。
線程:使用 threading.Thread 來在背景中運行伺服器監聽,這樣可以避免阻塞 Tkinter 的主循環。
使用繁體中文,要如何知道clinet端在upd-receiver.exe,在clinet端接收檔案的進度、檔案名稱、檔案大小,要如何讓伺服端知道大檔案傳輸的進度,並讓伺服端使用者的UI程式中呈現clietn端回傳的資料,並在當 client 端完成檔案接收後,計算接收檔案的校驗碼,並將校驗碼傳送回 server 端,server 再進行比對,以確定檔案是否正確傳輸,如果正確,在使用者UI界面上呈現傳輸完成,請根據接上的伺服端程式碼及client端程式碼(啟動後自動向伺服端報到),執行時背景執行,不產生終端機畫面,完成程式整併,謝謝
測試暫放
import socket
import subprocess
import os
import hashlib
import threading
import time
import uuid
class Client:
def __init__(self):
# 初始化 UDP socket 並綁定接收端口
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.client_socket.bind(("", 8500)) # 綁定接收端口
def get_mac_address(self):
# 獲取 MAC 地址
mac = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff) for elements in range(0, 2*6, 2)][::-1])
return mac
def get_computer_name(self):
# 獲取電腦名稱
return socket.gethostname()
def send_report(self):
# 發送報到訊息
while True:
try:
report_msg = f"{socket.gethostbyname(socket.gethostname())},{self.get_mac_address()},{self.get_computer_name()}"
print(f"發送報到訊息: {report_msg}") # 顯示發送的報告
self.client_socket.sendto(report_msg.encode(), ('<broadcast>', 37020))
except Exception as e:
print(f"發送報到時發生錯誤: {e}")
time.sleep(5)
def receive_file_list(self):
# 接收伺服端傳來的檔案清單
while True:
try:
data, addr = self.client_socket.recvfrom(1024)
file_list = data.decode().split(",")
print(f"接收到的檔案清單: {file_list}")
os.makedirs("received_files", exist_ok=True)
for file_name in file_list:
save_path = os.path.join("received_files", os.path.basename(file_name))
self.receive_file(save_path)
except Exception as e:
print(f"接收檔案清單時發生錯誤: {e}")
def receive_file(self, save_path):
# 使用 udp-receiver.exe 接收檔案
subprocess.run(['udp-receiver.exe', '--file', save_path, '--port', '8500'], creationflags=subprocess.CREATE_NO_WINDOW)
# 傳送接收進度
file_size = os.path.getsize(save_path)
self.send_progress(file_size, save_path)
# 計算檔案校驗碼並傳送回伺服端
checksum = self.calculate_checksum(save_path)
self.send_checksum(save_path, checksum)
def send_progress(self, file_size, file_name):
# 傳送接收進度到伺服端
progress = 100 # 這裡簡化為完成進度
report_msg = f"PROGRESS:{socket.gethostbyname(socket.gethostname())},{file_name},{progress}"
self.client_socket.sendto(report_msg.encode(), ('<broadcast>', 37020))
def calculate_checksum(self, file_name):
# 計算 MD5 校驗碼
hash_md5 = hashlib.md5()
with open(file_name, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def send_checksum(self, file_name, checksum):
# 傳送校驗碼到伺服端
report_msg = f"CHECKSUM:{socket.gethostbyname(socket.gethostname())},{file_name},{checksum}"
self.client_socket.sendto(report_msg.encode(), ('<broadcast>', 37020))
# 啟動客戶端
if __name__ == "__main__":
client = Client()
# 使用執行緒同時進行報到與檔案接收
threading.Thread(target=client.send_report, daemon=True).start()
threading.Thread(target=client.receive_file_list, daemon=True).start()
# 主程式保持運行
while True:
time.sleep(1)