Files
ComConfigCopy/TFTPServer.py
Lowa 029371fa68 Enhance error handling and retry mechanism for command execution
- Add a new `send_login_password()` function to centralize login/password input logic
- Implement retry mechanism for both line and block command modes
- Add support for detecting and handling command errors (marked by '^' symbol)
- Limit retry attempts to 3 times for each command
- Improve logging and error reporting for command execution
- Update interactive command processing in SerialAppGUI to include retry logic
2025-02-14 02:47:39 +03:00

99 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Модуль для TFTP-сервера.
"""
import socket
import threading
import os
import time
class TFTPServerThread(threading.Thread):
def __init__(self, host, port, log_callback):
super().__init__()
self.host = host
self.port = port
self.log_callback = log_callback
self.running = True
self.sock = None
def run(self):
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind((self.host, self.port))
self.log_callback(f"TFTP сервер запущен на {self.host}:{self.port}\n")
except Exception as e:
self.log_callback(f"Ошибка запуска TFTP сервера: {e}\n")
return
while self.running:
try:
self.sock.settimeout(1)
data, addr = self.sock.recvfrom(1024)
if data:
self.handle_rrq(data, addr)
except socket.timeout:
continue
except Exception as e:
self.log_callback(f"Ошибка: {e}\n")
if self.sock:
self.sock.close()
self.log_callback("TFTP сервер остановлен.\n")
def handle_rrq(self, data, addr):
opcode = int.from_bytes(data[0:2], byteorder='big')
if opcode != 1:
self.log_callback(f"Получен не RRQ запрос от {addr}\n")
return
parts = data[2:].split(b'\0')
if len(parts) < 2:
self.log_callback(f"Неверный формат RRQ от {addr}\n")
return
req_filename = parts[0].decode('utf-8', errors='ignore')
mode = parts[1].decode('utf-8', errors='ignore')
self.log_callback(f"Получен RRQ для файла '{req_filename}' (режим {mode}) от {addr}\n")
filepath = os.path.join("Firmware", req_filename)
if not os.path.exists(filepath):
self.log_callback(f"Файл '{req_filename}' не найден в папке Firmware\n")
return
try:
filesize = os.path.getsize(filepath)
f = open(filepath, 'rb')
except Exception as e:
self.log_callback(f"Ошибка открытия файла '{req_filename}': {e}\n")
return
block_num = 1
bytes_sent = 0
start_time = time.time()
while True:
block_data = f.read(512)
data_packet = b'\x00\x03' + block_num.to_bytes(2, byteorder='big') + block_data
self.sock.sendto(data_packet, addr)
self.log_callback(f"Отправлен блок {block_num} ({len(block_data)} байт)\n")
try:
self.sock.settimeout(5)
ack, ack_addr = self.sock.recvfrom(1024)
if ack_addr != addr:
continue
ack_opcode = int.from_bytes(ack[0:2], byteorder='big')
ack_block = int.from_bytes(ack[2:4], byteorder='big')
if ack_opcode != 4 or ack_block != block_num:
self.log_callback(f"Неверный ACK от {addr}\n")
break
except socket.timeout:
self.log_callback("Таймаут ожидания ACK\n")
break
bytes_sent += len(block_data)
elapsed = time.time() - start_time
speed = bytes_sent / elapsed if elapsed > 0 else 0
progress = (bytes_sent / filesize) * 100 if filesize > 0 else 0
self.log_callback(f"Прогресс: {progress:.2f}% | Скорость: {speed:.2f} байт/с\n")
if len(block_data) < 512:
break
block_num += 1
f.close()
def stop(self):
self.running = False