From c3a17c7ccfda53c59368e41066f1dcb61d4be315 Mon Sep 17 00:00:00 2001 From: Michael Zanger <michaelzanger@Michaels-MacBook-Air.fritz.box> Date: Tue, 16 Jan 2024 16:41:56 +0100 Subject: [PATCH] fix update cache --- server.py | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 7 deletions(-) diff --git a/server.py b/server.py index 51042d9..d129148 100644 --- a/server.py +++ b/server.py @@ -6,6 +6,7 @@ import time import ipaddress import netifaces as ni import platform +import uuid client_broadcast_listener_port = 49153 server_broadcast_listener_port = 49154 @@ -15,10 +16,16 @@ server_heartbeat_tcp_listener_port = 49152 client_receive_chat_tcp_port = 50001 client_forward_message_multicast_port = 51000 +leader_election_port = 49155 + multicast_group_ip = '224.0.1.1' last_heartbeat_timestamp = None +# create election sockets +ring_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +ring_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + class Server(multiprocessing.Process): client_cache_key_offset = 0 local_servers_cache = dict() @@ -38,6 +45,10 @@ class Server(multiprocessing.Process): self.local_servers_cache = server_cache self.local_clients_cache = clients_cache self.last_heartbeat_timestamp = last_heartbeat_timestamp + ring_socket.bind((self.server_address, leader_election_port)) + self.server_uuid = self.generate_server_uuid() + print("My UUID: ", self.server_uuid) + self.participant = True @staticmethod def get_local_ip_address(): @@ -104,6 +115,10 @@ class Server(multiprocessing.Process): return "macOS" else: return "Unknown" + + @staticmethod + def generate_server_uuid(): + return str(uuid.uuid4()) def run(self): print(self.server_id+": "+"Up and running") @@ -203,7 +218,8 @@ class Server(multiprocessing.Process): if current_time - self.last_heartbeat_timestamp >= timeout_duration: print(f"No heartbeats received for {timeout_duration} seconds. Initiating LCR...") # Call a function to initiate the LCR algorithm here - self.initiate_lcr_algorithm() + print(self.local_servers_cache) + self.start_leader_election(self.server_uuid, self.local_servers_cache) # find highest server ID in cache def get_last_server_id(self): @@ -393,13 +409,15 @@ class Server(multiprocessing.Process): separator = "_" MSG = servers_cache_as_string + separator.encode('utf-8') + clients_cache_as_string - broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + time.sleep(3) if self.os == "macOS": broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) broadcast_socket.sendto(MSG, (BROADCAST_ADDRESS, PORT)) + print("broadcast sent to", BROADCAST_ADDRESS, PORT, "with message", MSG) else: broadcast_socket.sendto(MSG, (BROADCAST_ADDRESS, PORT)) broadcast_socket.close() @@ -408,10 +426,11 @@ class Server(multiprocessing.Process): BROADCAST_ADDRESS = self.get_broadcast_address() BROADCAST_PORT = 5980 print("listen for cache update") + # Local host information - MY_HOST = socket.gethostname() - MY_IP = socket.gethostbyname(MY_HOST) - print("listen for cache update") + # MY_HOST = socket.gethostname() + # MY_IP = socket.gethostbyname(MY_HOST) + # Create a UDP socket listen_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Set the socket to broadcast and enable reusing addresses @@ -419,7 +438,6 @@ class Server(multiprocessing.Process): listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if self.os == "macOS": - print("listening for cache updates") listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) listen_socket.bind((BROADCAST_ADDRESS, BROADCAST_PORT)) else: @@ -496,4 +514,63 @@ class Server(multiprocessing.Process): multicast_socket.close() - \ No newline at end of file + def start_leader_election(self, server, neighbor_dict): + self.send_election_message(server, neighbor_dict['server_address']) + self.set_participant(True) + + def send_election_message(server, neighbor_address): + election_message = {"mid": server, "isLeader": False} + ring_socket.sendto(json.dumps(election_message).encode(), neighbor_address) + + def get_neighbour(servers, current_server, direction): + if not servers: + return None + + server_ids = list(servers.keys()) + current_index = server_ids.index(current_server) + + if direction == 'left': + neighbor_index = (current_index - 1) % len(server_ids) + elif direction == 'right': + neighbor_index = (current_index + 1) % len(server_ids) + else: + return None + + neighbor_server_id = server_ids[neighbor_index] + neighbor_server_info = servers[neighbor_server_id] + + return {'server_id': neighbor_server_id, 'server_address': neighbor_server_info} + + def set_participant(p): + global participant + participant = p + + def leader_election(self): + while True: + data, address = ring_socket.recvfrom(4096) + if data: + election_message = json.loads(data.decode()) + received_mid = election_message.get('mid') + received_mid_id = received_mid['server_uuid'] # Correctly access the server UUID + + # Compare received_mid_id with self.server_uuid (UUID comparison) + if received_mid_id > self.server_uuid: + self.send_election_message(self.server_uuid, self.get_neighbour(self.local_servers_cache, self.server_uuid, 'left')['server_address']) + elif received_mid_id == self.server_uuid and self.participant: + self.send_election_message(self.server_uuid, self.get_neighbour(self.local_servers_cache, self.server_uuid, 'left')['server_address']) + elif received_mid_id < self.server_uuid and not self.participant: + self.send_election_message(self.server_uuid, self.get_neighbour(self.local_servers_cache, self.server_uuid, 'left')['server_address']) + + # Determine participant status and leader + self.participant = True # You may adjust this logic + if election_message['isLeader']: + self.set_leader(election_message['mid']) + if self.server_uuid != received_mid_id: + self.set_is_leader(False) + self.send_election_message(self.server_uuid, self.get_neighbour(self.local_servers_cache, self.server_uuid, 'left')['server_address']) + else: + self.set_is_leader(True) + self.participant = False # You may set this as not a participant + + + -- GitLab