From 4e3b5b9c8c83ae51887a7578bfb481ab7facc4ef Mon Sep 17 00:00:00 2001 From: Quoc Dao <quoc.dao@student.reutlingen-university.de> Date: Tue, 23 Jan 2024 00:29:04 +0100 Subject: [PATCH] mit server-server-dd --- client.py | 100 ++++++++++++++++++++-------------------------- server.py | 117 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 114 insertions(+), 103 deletions(-) diff --git a/client.py b/client.py index c2f81ac..6b342a2 100644 --- a/client.py +++ b/client.py @@ -2,9 +2,11 @@ import socket import threading from datetime import datetime -# Broadcast address and port -BROADCAST_IP = "192.168.0.255" -BROADCAST_PORT = 5973 + +# Broadcast address and port for client broadcasts +BROADCAST_IP_CLIENT = "192.168.0.255" +BROADCAST_PORT_CLIENT = 5973 + # Local host information MY_HOST = socket.gethostname() @@ -17,73 +19,62 @@ class Client(): self.currentLeader = '' self.server_socket = None + # print the current date and time def printwt(self, msg): current_date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') print(f'[{current_date_time}] {msg}') + # dynamic discoverey: client sends request to server group and gets the IP of server as reply def BroadcastSendAndReceive(self): - message = 'New client wants to connect: ' + MY_IP # Create a UDP socket - broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + client_broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Send message on broadcast address - broadcast_socket.sendto(str.encode(message), (BROADCAST_IP, BROADCAST_PORT)) + client_broadcast_socket.sendto(str.encode(message), (BROADCAST_IP_CLIENT, BROADCAST_PORT_CLIENT)) # Send broadcast message self.printwt("Sent my IP to server group") - while True: - try: - # receive reply data (server IP) from the other participants - reply, addr = broadcast_socket.recvfrom(1024) - - if reply: - # decode received data - reply_addr = reply.decode() - self.currentLeader = reply_addr - self.printwt(f'Got Leader address: {self.currentLeader}') - - # Connect to the server using TCP - self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.server_socket.connect((self.currentLeader, 5555)) - print("You have entered the chat room") - - # Starte einen Thread, um Nachrichten zu empfangen - receive_thread = threading.Thread(target=self.receive_messages) - receive_thread.start() - - # Haupt-Thread zum Senden von Nachrichten - while True: - message = input() - timestamped_message = f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] {message}' - self.server_socket.send(timestamped_message.encode('utf-8')) - - except socket.timeout: - pass - - def discover_group_members(self): - # Send a broadcast message to discover group members - group_discovery_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - group_discovery_socket.settimeout(3) # Set timeout to 3 seconds - group_discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - group_discovery_socket.sendto(str.encode("Any group members here?"), ('<broadcast>', BROADCAST_PORT)) - + # while True: + # Receive server leader's IP try: - while True: - data, addr = group_discovery_socket.recvfrom(1024) - if data: - group_member_IP = data.decode() - if group_member_IP != MY_IP and group_member_IP not in self.group_members: - self.group_members[group_member_IP] = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - self.printwt(f'New group member found: {group_member_IP}') - # Respond to the new member with own IP - group_discovery_socket.sendto(str.encode(MY_IP), (group_member_IP, BROADCAST_PORT)) + data, addr = client_broadcast_socket.recvfrom(1024) + if data: + self.current_leader = data.decode() + self.printwt(f'Got Server Leader address: {self.current_leader}') + + + # receive reply data (server IP) from the other participants + # reply, addr = client_broadcast_socket.recvfrom(1024) + + # if reply: + # # decode received data + # reply_addr = reply.decode() + # self.currentLeader = reply_addr + # self.printwt(f'Got Leader address: {self.currentLeader}') + + # Connect to the server using TCP + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.server_socket.connect((self.currentLeader, 5555)) + print("You have entered the chat room") + + # Starte einen Thread, um Nachrichten zu empfangen + receive_thread = threading.Thread(target=self.receive_messages) + receive_thread.start() + + # Main thread for sending messages + while True: + message = input() + timestamped_message = f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] {message}' + self.server_socket.send(timestamped_message.encode('utf-8')) + except socket.timeout: - group_discovery_socket.close() + pass + def receive_messages(self): while True: @@ -102,11 +93,6 @@ class Client(): if __name__ == "__main__": client = Client() - # Start a thread to discover group members - discovery_thread = threading.Thread(target=client.discover_group_members) - discovery_thread.start() - - # Start the thread to send and receive messages thread1 = threading.Thread(target = client.BroadcastSendAndReceive) thread1.start() thread1.join() \ No newline at end of file diff --git a/server.py b/server.py index 5b0a521..5551540 100644 --- a/server.py +++ b/server.py @@ -3,8 +3,10 @@ import threading from datetime import datetime import time -# Listening port -BROADCAST_PORT = 5973 +# Listening port for client broadcasts +BROADCAST_PORT_CLIENT = 5973 +# Listening port for server broadcasts +BROADCAST_PORT_SERVER = 5974 # Local host information MY_HOST = socket.gethostname() @@ -15,6 +17,7 @@ class Server(): self.group_members = {} # Dictionary to store group members with their IPs as keys self.leader_IP = '' # fix the leader IP self.clients = [] + self.is_leader = False # Flag to indicate if this server is the leader def printwt(self, msg): @@ -22,38 +25,74 @@ class Server(): print(f'[{current_date_time}] {msg}') + def announce_leader(self): + # Announce leader to clients + while True: + if self.is_leader: + self.broadcast_leader() + time.sleep(5) + + + def broadcast_leader(self): + # Broadcast the leader's IP to clients + for client_socket in self.clients: + try: + client_socket.send(self.leader_IP.encode()) + except: + self.clients.remove(client_socket) + + + def ListenForServerBroadcastAndReply(self): + # Listen to server broadcasts and reply with own IP + server_broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + server_broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server_broadcast_socket.bind(('', BROADCAST_PORT_SERVER)) + + while True: + data, addr = server_broadcast_socket.recvfrom(1024) + if data: + # Decode received data (new server's IP) + new_server_ip = data.decode() + self.group_members[new_server_ip] = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + + # Respond to the new member with own IP + server_broadcast_socket.sendto(MY_IP.encode(), addr) + self.printwt(f'New group member found: {new_server_ip}') + self.print_group_members() + + def print_group_members(self): self.printwt("Current group members:") for member, timestamp in self.group_members.items(): self.printwt(f'{member} (joined at {timestamp})') + def become_leader(self): + # Announce to the group that this server is the leader + self.is_leader = True + self.leader_IP = MY_IP + self.broadcast_leader() + + # Listen to client broadcast (request) and reply with Server IP - def ListenForClientAndReply(self): + def listen_for_client_broadcasts(self): # Create a UDP socket - listen_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + client_broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Set the socket to broadcast and enable reusing addresses - listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + client_broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Bind socket to address and port - listen_socket.bind((MY_IP, BROADCAST_PORT)) + client_broadcast_socket.bind(('', BROADCAST_PORT_CLIENT)) print("Listening to broadcast messages") # Receiving broadcast massage while True: - data, addr = listen_socket.recvfrom(1024) - - if data: - self.printwt(data.decode()) + data, addr = client_broadcast_socket.recvfrom(1024) - # if Iam the leader, answer the client including my IP - if MY_IP == self.leader_IP: - reply_message = MY_IP - listen_socket.sendto(str.encode(reply_message), addr) + if data and self.is_leader: + client_broadcast_socket.sendto(self.leader_IP.encode(), addr) self.printwt('Replied my IP to new client') - def handle_client(self, client_socket, client_address): self.clients.append(client_socket) @@ -68,7 +107,6 @@ class Server(): self.clients.remove(client_socket) break - def broadcast(self, message, sender_socket): for client in self.clients: try: @@ -78,49 +116,36 @@ class Server(): self.clients.remove(client) - def announce_leader(self): - # Send a broadcast message to determine the leader - leader_broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - leader_broadcast_socket.settimeout(3) # Set timeout to 3 seconds - leader_broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - leader_broadcast_socket.sendto(str.encode("Who is the leader?"), ('<broadcast>', BROADCAST_PORT)) - - try: - data, addr = leader_broadcast_socket.recvfrom(1024) - if data: - self.leader_IP = addr[0] - self.group_members[self.leader_IP] = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - self.printwt(f'Leader elected: {self.leader_IP}') - - except socket.timeout: - # If no response received, assume this server is the leader - self.leader_IP = MY_IP - self.group_members[self.leader_IP] = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - self.printwt(f'I am the first server and leader: {self.leader_IP}') - - leader_broadcast_socket.close() - # starting all simultaneously working procedures if __name__== '__main__': server = Server() - # Start a thread to announce the leader + + # Start a thread to announce the leader to clients leader_thread = threading.Thread(target=server.announce_leader) leader_thread.start() - # Start the thread to listen for client broadcasts - thread1 = threading.Thread(target = server.ListenForClientAndReply) - thread1.start() - # Start a thread to periodically print the group members - print_group_thread = threading.Thread(target=server.print_group_members) - print_group_thread.start() + # Start a thread to listen for server broadcasts + server_broadcast_thread = threading.Thread(target=server.ListenForServerBroadcastAndReply) + server_broadcast_thread.start() + + + client_broadcast_thread = threading.Thread(target = server.listen_for_client_broadcasts) + client_broadcast_thread.start() + # Socket erstellen und binden server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((MY_IP, 5555)) server_socket.listen(5) + + # Check if this server is the first in the group and become the leader + time.sleep(3) # Wait for other servers to potentially announce themselves + if not server.group_members: + server.become_leader() + while True: client_socket, client_address = server_socket.accept() -- GitLab