простой клиент и сервер tcp
This commit is contained in:
parent
05bd0435c1
commit
2bdf5fd4fd
20
README.md
20
README.md
@ -1,2 +1,20 @@
|
||||
# innopol-protocol-mayak-server
|
||||
# about
|
||||
|
||||
## server.py
|
||||
|
||||
Запускаем на удаленном сервере
|
||||
Слушает указанный порт, ждет подключение клиента, печатает принятое сообщение, при получении отправляет заданное сообщение
|
||||
|
||||
```
|
||||
python3 server.py --host 0.0.0.0 --port 5000 --response "OK, пакет получен"
|
||||
```
|
||||
|
||||
## client.py
|
||||
|
||||
Запускаем на локальной машине
|
||||
Указываем адрес сервера, порт сообщение которое отправляем и интервал повторения отправки
|
||||
|
||||
```
|
||||
python3 client.py --host 127.0.0.1 --port 5000 --message "ping" --interval 5
|
||||
```
|
||||
|
||||
|
||||
88
client.py
Normal file
88
client.py
Normal file
@ -0,0 +1,88 @@
|
||||
#!/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()
|
||||
63
server.py
Normal file
63
server.py
Normal file
@ -0,0 +1,63 @@
|
||||
#!/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()
|
||||
Loading…
Reference in New Issue
Block a user