Function for sending an acknowledgment for a received message.
"""
right_neighbour=neighbour.get_neighbour(members_IP,ip_address,'right')# Determine the right neighbor based on the current ring structure
msg=("Your Message was received.")# Message sent as a receipt confirmation
send_ack_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# Create a UDP socket to send the acknowledgment
send_ack_socket.sendto(msg.encode('utf-8'),(right_neighbour,acknowledgement_port))# Send the acknowledgment message to the right neighbor using the acknowledgement_port
send_ack_socket.close()# Close the socket after sending the message
defreceive_acknowledgement(msg,ip,so):
"""
Function for receiving acknowledgments. This section includes the system's response to messages not received between servers.
"""
globalmembers_IP
globalis_leader
right_neighbour=neighbour.get_neighbour(members_IP,ip_address,'right')# Determine the right neighbor based on the current ring structure
recack_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# Create a socket to receive acknowledgment messages
temp_send_socket.sendto(msg,(new_neighbour,so))# Forward the original message to the new neighbor
temp_send_socket.close()
receive_acknowledgement(msg,new_neighbour,so)# Wait for acknowledgment from the new neighbor
########################### End - Acknowledgement ###########################
########################### Start - Update ring ###########################
deflausche_update_Ring():
"""
Listens for ring updates via UDP broadcasts and handles updates to the members_IP list.
"""
globalmembers_IP
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# Create a UDP socket for communication
sock.bind((ip_address,ringport))# Bind the socket to the servers IP address and ring port for listening
whileTrue:
try:
data,addr=sock.recvfrom(1024)# Receive data from the socket
members_IP2=json.loads(data.decode())# Decode the received JSON data to update the members list
ifmembers_IP2==members_IP:# Check if the received members list matches the current members list
print(f"Ring update has traveled through the ring.")
send_acknowledgement()# Send an acknowledgment for the received update
else:
members_IP=members_IP2# Update the local members list
print(f"Ring update received: {members_IP}")
send_acknowledgement()# Send an acknowledgment for the received update
send_update_to_ring()# Forward the updated member list to the next neighbor
exceptjson.JSONDecodeError:
print("Error decoding the JSON data.")# Handle errors in decoding the JSON data
defsend_update_to_ring():
"""
Sends the updated members list to the next server in the ring.
"""
globalmembers_IP
right_neighbour=neighbour.get_neighbour(members_IP,ip_address,'right')# Determine the right neighbor based on the current ring structure
ifnotright_neighbour:# If no right neighbor exists, there is no one to send the update to
print("No left neighbour to send updates.")
return
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# Create a UDP socket for sending updates
data=json.dumps(members_IP).encode()# Serialize the members list into JSON format
try:
sock.sendto(data,(right_neighbour,ringport))# Send the members list to the right neighbor
receive_acknowledgement(data,right_neighbour,ringport)# Wait for acknowledgment from the right neighbor
exceptExceptionase:# Handle errors during data transmission
print(f"Error sending data: {e}")
sock.close()# Close the socket to free up resources
########################### End - Update ring ###########################
########################### Start - Server Enters ###########################
defnew_server_in_ring():
"""
This function is executed by the Leader. It listens for incoming messages from servers attempting to join the network.
The Leader maintains the list of all IP addresses in the ring and updates the topology whenever a new server joins.
Topology Updates: The Leader ensures all servers in the network are aware of the latest ring structure.
"""
globalmembers_UUID
globalmembers_IP
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# Create a UDP socket
sock.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)# Set the socket to broadcast mode
sock.bind(("0.0.0.0",enter_port))# Bind the socket to the address "0.0.0.0" and the enter_port
print("Server is running and waiting for broadcast messages from new servers.")
whileTrue:
data,addr=sock.recvfrom(1024)# Listen for messages from other servers
print(f"Message received from {addr}: {data.decode()}")
new_server_ip,new_server_port=addr# Extract the IP and port of the new server from the received address
new_IP=data.decode()
new_IP=new_IP.split(": ")[1]# Extract the IP address from the message
ifnew_IPinmembers_IP:# Check if the IP already exists. This might happen if a server temporarily lost connection. #######Tritt das überhaupt ein? In Gruppe diskutieren
msg=json.dumps(members_IP).encode()# If the server already exists, send the updated member list
else:
members_IP.append(new_IP)# If the server is new, add its IP to the list
msg=f"There are already servers. I am the leader: {ip_address}"# Create a message for the new server
sock.sendto(msg.encode(),(new_IP,new_server_port))# Send the greeting message back to the new server
print(f"The updated IP_Ring is: {members_IP}")
send_update_to_ring()# Update the ring topology
defserver_enters():
"""
This function is used when a server wants to join the network. It sends a greeting message to the broadcast address and waits for a response from the Leader.
If no response is received, the server assumes the Leader role and starts managing the ring itself.
Broadcast Communication: This allows new servers to discover the Leader without knowing its specific IP address.
"""
globalmembers_UUID
globalleader_ip
msg=f"I am new: {ip_address}".encode()# Greeting message from the new server
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# Create a UDP socket
sock.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)# Set the socket to broadcast mode
sock.sendto(msg,(broadcast_ip,enter_port))# Send the greeting message to the broadcast address using the enter_port
sock.settimeout(1)# Set a timeout to wait for a response --> ggf. anpassen, je nach geschwindigkeit mit Handy Internet
try:
data,addr=sock.recvfrom(1024)# receiving response
print(f"Antwort von {addr}: {data.decode()}")
sock.close()
my_leader=data.decode().split(": ")[1]# Extract the Leader's IP address from the response
leader_ip=my_leader# Set leder_ip to the received IP
exceptsocket.timeout:
print(f"Keine Antwort erhalten. Ich bin jetzt der Leader. Meine IP: {ip_address}")# If no answer is received the server sets itself as leader
members_UUID.append(my_ID)# Add itself as a participant in the ring
members_IP.append(ip_address)# Add itself as a participant in the ring
sock.close()
is_leader.set_value(True)# Mark itself as the Leader
leader_ip=ip_address# Set leder_ip to own IP
new_server_in_ring()# Start the function to manage new servers in the ring --> Achtung nur für tests! #####################################################################
########################### End - Server Enters ###########################