innopol-protocol-mayak-server/client.py

89 lines
3.3 KiB
Python
Raw Permalink 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
import socket
import struct
import argparse
import time
import sys
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 connect(host, port, timeout=10):
return socket.create_connection((host, port), timeout=timeout)
def main():
ap = argparse.ArgumentParser(description="TCP клиент (длина+данные) с периодической отправкой.")
ap.add_argument("--host", default="127.0.0.1", help="Адрес сервера")
ap.add_argument("--port", type=int, default=5000, help="Порт сервера")
ap.add_argument("--message", default="Привет от клиента!", help="Сообщение (UTF-8)")
ap.add_argument("--interval", type=float, default=5.0, help="Интервал отправки, сек (по умолчанию 5)")
args = ap.parse_args()
msg_bytes = args.message.encode("utf-8")
sock = None
try:
while True:
# Подключаемся, если не подключены
if sock is None:
try:
sock = connect(args.host, args.port, timeout=10)
sock.settimeout(15) # таймаут на операции, чтобы не зависать навсегда
print(f"Подключено к {args.host}:{args.port}")
except Exception as e:
print(f"Не удалось подключиться: {e}. Повтор через {args.interval} сек.")
time.sleep(args.interval)
continue
# Пытаемся отправить/получить
try:
send_packet(sock, msg_bytes)
print(f"Отправлено серверу: {args.message!r}")
resp = recv_packet(sock)
try:
print(f"Ответ сервера: {resp.decode('utf-8')!r}")
except UnicodeDecodeError:
print(f"Ответ сервера (bytes): {resp!r}")
time.sleep(args.interval)
except (ConnectionError, BrokenPipeError, TimeoutError, socket.timeout) as e:
print(f"Потеряно соединение: {e}. Переподключение через {args.interval} сек.")
try:
sock.close()
except Exception:
pass
sock = None
time.sleep(args.interval)
except KeyboardInterrupt:
print("\nЗавершение по Ctrl+C.")
finally:
if sock:
try:
sock.close()
except Exception:
pass
if __name__ == "__main__":
main()