#!/usr/bin/env python3 import socket import struct import argparse import threading def recv_exact(sock, nbytes): chunks, got = [], 0 while got < nbytes: chunk = sock.recv(nbytes - got) if not chunk: raise ConnectionError("Клиент закрыл соединение") chunks.append(chunk) got += len(chunk) return b"".join(chunks) def recv_packet(sock): raw_len = recv_exact(sock, 4) (length,) = struct.unpack("!I", raw_len) if length > 16 * 1024 * 1024: raise ValueError(f"Слишком большой пакет: {length} байт") return recv_exact(sock, length) def send_packet(sock, data: bytes): sock.sendall(struct.pack("!I", len(data)) + data) def handle_client(conn, addr, response_text: str): print(f"[+] Подключился {addr[0]}:{addr[1]}") try: while True: data = recv_packet(conn) # ждём следующий пакет try: print(f"[{addr[0]}:{addr[1]}] получил: {data.decode('utf-8')!r}") except UnicodeDecodeError: print(f"[{addr[0]}:{addr[1]}] получил (bytes): {data!r}") send_packet(conn, response_text.encode("utf-8")) except (ConnectionError, OSError) as e: print(f"[-] {addr[0]}:{addr[1]} отключился: {e}") finally: conn.close() def main(): ap = argparse.ArgumentParser(description="TCP сервер (длина+данные), держит соединение.") ap.add_argument("--host", default="0.0.0.0") ap.add_argument("--port", type=int, default=5000) ap.add_argument("--response", default="OK, пакет получен") args = ap.parse_args() with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as srv: srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.bind((args.host, args.port)) srv.listen(16) print(f"Сервер слушает {args.host}:{args.port} ... (Ctrl+C для выхода)") try: while True: conn, addr = srv.accept() t = threading.Thread(target=handle_client, args=(conn, addr, args.response), daemon=True) t.start() except KeyboardInterrupt: print("\nОстановка сервера.") if __name__ == "__main__": main()