80 lines
2.3 KiB
Python
80 lines
2.3 KiB
Python
# sender/client.py — TCP socket client, connects to receiver and sends data
|
|
|
|
import socket
|
|
import time
|
|
import logging
|
|
import sys
|
|
import os
|
|
import argparse
|
|
|
|
from config import HOST, PORT, SEND_INTERVAL, ACK_BYTE, RECONNECT_DELAY, BUFFER_SIZE
|
|
from generator import generate_data
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--id", required=True, help="Device ID")
|
|
args = parser.parse_args()
|
|
|
|
DEVICE_ID = args.id
|
|
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="[SENDER] %(asctime)s — %(message)s",
|
|
datefmt="%H:%M:%S"
|
|
)
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def connect_to_server() -> socket.socket:
|
|
"""Keep trying to connect until server is available."""
|
|
while True:
|
|
try:
|
|
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
client.connect((HOST, PORT))
|
|
log.info(f"Connected to server at {HOST}:{PORT}")
|
|
return client
|
|
except ConnectionRefusedError:
|
|
log.warning(f"Server not available. Retrying in {RECONNECT_DELAY}s...")
|
|
time.sleep(RECONNECT_DELAY)
|
|
|
|
|
|
def run():
|
|
log.info(f"Sender starting with DEVICE_ID={DEVICE_ID}...")
|
|
|
|
while True:
|
|
client = connect_to_server()
|
|
|
|
try:
|
|
while True:
|
|
# 1. Generate data string with unique ID
|
|
data = generate_data(DEVICE_ID)
|
|
display = data.replace('\0', '\\0')
|
|
log.info(f"Sending → {display}")
|
|
|
|
# 2. Send encoded bytes
|
|
client.sendall(data.encode('utf-8'))
|
|
|
|
# 3. Wait for ACK
|
|
try:
|
|
client.settimeout(5.0)
|
|
ack = client.recv(BUFFER_SIZE)
|
|
if ack == ACK_BYTE:
|
|
log.info("ACK received")
|
|
else:
|
|
log.warning(f"Unexpected response: {ack}")
|
|
except socket.timeout:
|
|
log.error("ACK timeout — server may be down")
|
|
break
|
|
|
|
# 4. Wait before next send
|
|
time.sleep(SEND_INTERVAL)
|
|
|
|
except (ConnectionResetError, BrokenPipeError, OSError) as e:
|
|
log.error(f"Connection lost: {e}. Reconnecting...")
|
|
finally:
|
|
client.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run() |