diff --git a/Connectivity/SampleServerPi.py b/Connectivity/SampleServerPi.py index 9868fc29950c140b3d0695d631bebecb68e473a2..40bc7121ada6ad849e320fdb1f0c2f3df27dcdf0 100644 --- a/Connectivity/SampleServerPi.py +++ b/Connectivity/SampleServerPi.py @@ -1,106 +1,174 @@ +import queue import socket import threading import time -UDP_IP = "255.255.255.255" -UDP_PORT = 5005 -LISTEN_PORT = 5006 - -def broadcast_presence(): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - - while True: - message = b"ROBOBIN_PRESENT" - sock.sendto(message, (UDP_IP, UDP_PORT)) - print("Broadcasting: {}".format(message.decode())) - time.sleep(5) - -def handle_ping(client_socket): - print("Received PING from client.") - response = b"PONG" - print("Sending PONG to client.") - client_socket.sendall(response) - -def handle_time_request(client_socket): - current_time = time.ctime().encode() - print(f"Sending current time: {current_time.decode()}") - client_socket.sendall(current_time) - -def handle_custom_message(client_socket, message): - response = f"Received custom message: {message}".encode() - print(f"Custom handler response: {response.decode()}") - client_socket.sendall(response) -def handle_unknown_message(client_socket): - response = b"I don't know this message." - print("Sending response to unknown message.") - client_socket.sendall(response) - -message_handlers = { - "PING": handle_ping, - "TIME": handle_time_request, - "CUSTOM": handle_custom_message, -} - -def handle_client_connection(client_socket): - try: - while True: - request = client_socket.recv(1024) - if not request: - print("No request received, closing connection.") - break - message = request.decode() - print("Received from client: {}".format(message)) - - - parts = message.split(" ", 1) - message_type = parts[0] - message_data = parts[1] if len(parts) > 1 else None - - if message_type in message_handlers: - if message_type == "CUSTOM" and message_data: - message_handlers[message_type](client_socket, message_data) - else: - message_handlers[message_type](client_socket) - else: - handle_unknown_message(client_socket) - - except ConnectionResetError: - print("Client connection was forcibly closed.") - except Exception as e: - print(f"An error occurred while handling the client connection: {e}") - finally: - client_socket.close() - print("Client disconnected.") - -def listen_for_connections(): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.bind(('', LISTEN_PORT)) - - while True: +class RoboBinConnectionHandler: + def __init__(self, udp_ip="255.255.255.255", udp_port=5005, listen_port=5006): + self.queue = queue.Queue(10) + self.UDP_IP = udp_ip + self.UDP_PORT = udp_port + self.LISTEN_PORT = listen_port + self.stop_event = threading.Event() + self.message_handlers = { + "PING": self.handle_ping, + "TIME": self.handle_time_request, + "CALLOVER" : self.handle_call_over, + "CUSTOM": self.handle_custom_message, + + } + self.udp_sock = None + self.tcp_socket = None # + + def broadcast_presence(self): + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + while not self.stop_event.is_set(): + message = b"ROBOBIN_PRESENT" + try: + sock.sendto(message, (self.UDP_IP, self.UDP_PORT)) + print("Broadcasting: {}".format(message.decode())) + except OSError as e: + print(f"Broadcast error: {e}") + break + time.sleep(5) + + sock.close() + print("Broadcasting stopped.") + + def handle_ping(self, client_socket): + print("Received PING from client.") + response = b"PONG" + print("Sending PONG to client.") + client_socket.sendall(response) + + def handle_time_request(self, client_socket): + current_time = time.ctime().encode() + print(f"Sending current time: {current_time.decode()}") + client_socket.sendall(current_time) + + def handle_custom_message(self, client_socket, message): + response = f"Received custom message: {message}".encode() + print(f"Custom handler response: {response.decode()}") + client_socket.sendall(response) + + def handle_call_over(self, client_socket, message): + response = f"User has requested node: {message}".encode() + print(f"Call over handler response: {response.decode()}") + client_socket.sendall(response) + + def handle_unknown_message(self, client_socket): + response = b"I don't know this message." + print("Sending response to unknown message.") + client_socket.sendall(response) + + def handle_client_connection(self, client_socket): try: - data, addr = sock.recvfrom(1024) - if data.decode() == "CONNECT": - print("Received connection request from {}".format(addr)) + while not self.stop_event.is_set(): + client_socket.settimeout(1) + try: + request = client_socket.recv(1024) + except socket.timeout: + continue + except OSError as e: + print(f"Client socket error: {e}") + break + + if not request: + print("No request received, closing connection.") + break + message = request.decode() + print("Received from client: {}".format(message)) + + parts = message.split(" ", 1) + message_type = parts[0] + message_data = parts[1] if len(parts) > 1 else None + + if message_type in self.message_handlers: + if message_data: + self.message_handlers[message_type](client_socket, message_data) + else: + self.message_handlers[message_type](client_socket) + else: + self.handle_unknown_message(client_socket) - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as tcp_socket: - tcp_socket.bind(('', 5006)) - tcp_socket.listen(1) + except ConnectionResetError: + print("Client connection was forcibly closed.") + except Exception as e: + print(f"An error occurred while handling the client connection: {e}") + finally: + client_socket.close() + print("Client disconnected.") + + def listen_for_connections(self): + self.udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.udp_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.udp_sock.bind(('', self.LISTEN_PORT)) + + while not self.stop_event.is_set(): + try: + self.udp_sock.settimeout(1) # Timeout for blocking recvfrom call + data, addr = self.udp_sock.recvfrom(1024) + if data.decode() == "CONNECT": + print("Received connection request from {}".format(addr)) + + self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.tcp_socket.bind(('', self.LISTEN_PORT)) + self.tcp_socket.listen(1) print("Listening for TCP connection...") - client_socket, client_addr = tcp_socket.accept() + client_socket, client_addr = self.tcp_socket.accept() print("Client connected from {}".format(client_addr)) - threading.Thread(target=handle_client_connection, args=(client_socket,)).start() - except Exception as e: - print(f"An error occurred while listening for connections: {e}") - -# Start broadcasting and listening threads -broadcast_thread = threading.Thread(target=broadcast_presence) -listen_thread = threading.Thread(target=listen_for_connections) - -broadcast_thread.start() -listen_thread.start() - -broadcast_thread.join() -listen_thread.join() + threading.Thread(target=self.handle_client_connection, args=(client_socket,)).start() + except socket.timeout: + continue + except OSError as e: + print(f"UDP socket no longer open (likely due to stop event):" ) + break + except Exception as e: + print(f"An error occurred while listening for connections: {e}") + + # Close sockets if stop event is set + if self.udp_sock: + self.udp_sock.close() + if self.tcp_socket: + self.tcp_socket.close() + print("Listening stopped.") + + def start(self): + self.broadcast_thread = threading.Thread(target=self.broadcast_presence) + self.listen_thread = threading.Thread(target=self.listen_for_connections) + + self.broadcast_thread.start() + self.listen_thread.start() + + def stop(self): + print("Stopping server...") + self.stop_event.set() + # Safely close the sockets to prevent further operations on closed sockets + if self.udp_sock: + self.udp_sock.close() + if self.tcp_socket: + self.tcp_socket.close() + self.broadcast_thread.join() + self.listen_thread.join() + print("Server stopped.") + +# Instantiate and start the handler +if __name__ == "__main__": + robobin_handler = RoboBinConnectionHandler() + robobin_handler.start() + print("Server started. Type 'stop' to shut down.") + + # Main loop to accept CLI input + while True: + command = input("Enter command: ") + if command.strip().lower() == "stop": + robobin_handler.stop() + elif command.strip().lower() == "status": + print("Server is running.") + #printstatus() # Funciton will be added later + break