89 lines
3.3 KiB
Python
89 lines
3.3 KiB
Python
#!/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()
|