DC Exp3
DC Exp3
DATE:
ROLL NO: B803
EXPERIMENT NO. 03
THEORY:
GROUP COMMUNICATION:
Group Communication refers to a message-passing mechanism where multiple processes
communicate with each other in a distributed system. Unlike traditional one-to-one
communication (unicast), group communication allows a single sender to communicate with
multiple receivers (multicast), multiple senders to communicate with a single receiver (many-
to-one), or multiple senders and receivers to interact simultaneously (many-to-many).
It is widely used in distributed computing environments for tasks like data replication, resource
discovery, and fault tolerance. Group communication can be classified into open and closed
groups, where open groups allow external processes to send messages to the group, while
closed groups restrict communication to members only. Various mechanisms such as multicast
addresses, broadcasting, and message sequencing ensure efficient delivery, reliability, and
ordering of messages. Depending on application needs, group communication can also support
different levels of reliability, including atomic multicast, ensuring all members receive a
message or none at all.
2. Consistent Ordering
• Ensures all messages are delivered in the
same order to all receivers, but this order may
differ from the original sending order.
• Implementation: A sequencer assigns
sequence numbers to messages before
multicasting them.
The ABCAST protocol (from the ISIS
system) uses distributed agreement to
determine message order.
• Use Case: Distributed databases need to
ensure updates arrive in the same order at all
replicas to maintain consistency.
3. Causal Ordering
• Guarantees that messages with causal relationships are delivered in the correct order, but
unrelated messages may arrive in any sequence.
• Implementation: The CBCAST protocol (from the ISIS system) tracks causal
dependencies using vector timestamps.
Messages are buffered until dependencies are resolved.
• Use Case: Collaborative editing software ensures that changes influenced by earlier edits
appear in the correct order while allowing independent edits to be processed flexibly.
CODE:
Part A: Absolute Ordering
server.py
import socket
import threading
from datetime import datetime
class AbsoluteOrderingServer:
def __init__(self, host="127.0.0.1", port=23456):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((host, port))
self.server_socket.listen(5)
self.clients = []
self.client_ids = {} # Map sockets to client IDs
self.message_counter = 0
print(f"Server running at {host}:{port}")
def run(self):
client_number = 1
while True:
client_socket, _ = self.server_socket.accept()
client_id = f"Client {client_number}"
self.clients.append(client_socket)
print(f"{client_id} connected.")
threading.Thread(target=self.handle_client, args=(client_socket, client_id)).start()
client_number += 1
if __name__ == "__main__":
server = AbsoluteOrderingServer()
server.run()
client.py
import socket
import threading
class AbsoluteOrderingClient:
def __init__(self, server_ip="127.0.0.1", port=23456):
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((server_ip, port))
threading.Thread(target=self.receive_messages).start()
def receive_messages(self):
while True:
try:
message = self.client_socket.recv(1024).decode()
if not message:
break
print(f"Ordered Message Received: {message}")
except:
break
if __name__ == "__main__":
client = AbsoluteOrderingClient()
while True:
msg = input("Enter message: ")
client.send_message(msg)
OUTPUT:
Server
class ConsistentOrderingServer:
def __init__(self, host="127.0.0.1", port=23457):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((host, port))
self.server_socket.listen(5)
self.clients = []
self.client_ids = {}
self.client_counter = 1
print(f"Consistent Ordering Server running at {host}:{port}")
def run(self):
while True:
client_socket, _ = self.server_socket.accept()
client_id = f"Client-{self.client_counter}"
self.client_counter += 1
self.clients.append(client_socket)
print(f"{client_id} connected.")
threading.Thread(target=self.handle_client, args=(client_socket, client_id)).start()
if __name__ == "__main__":
server = ConsistentOrderingServer()
server.run()
client.py
import socket
import threading
class ConsistentOrderingClient:
def __init__(self, server_ip="127.0.0.1", port=23457):
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((server_ip, port))
threading.Thread(target=self.receive_messages).start()
def receive_messages(self):
while True:
try:
message = self.client_socket.recv(1024).decode()
if not message:
break
print(f"Message Received: {message}")
except:
break
if __name__ == "__main__":
client = ConsistentOrderingClient()
while True:
msg = input("Enter message: ")
client.send_message(msg)
OUTPUT:
Server
class CausalOrderingServer:
def __init__(self, host="127.0.0.1", port=23458):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((host, port))
self.server_socket.listen()
self.clients = {}
self.vector_clock = defaultdict(int)
self.buffer = []
self.lock = threading.Lock()
self.current_id = 0
print(f"Causal Ordering Server running at {host}:{port}")
def assign_client_id(self):
with self.lock:
client_id = self.current_id
self.current_id += 1
return client_id
if can_process:
print(f"Processing message from Client-{client_id}: {msg_text}")
self.vector_clock[client_id] += 1
broadcast_msg = json.dumps({
'vector': self.vector_clock.copy(),
'message': msg_text,
'sender': f"Client-{client_id}"
}).encode()
self.broadcast(broadcast_msg)
self.check_buffer()
else:
print(f"Buffering message from Client-{client_id}: {msg_text} (Unmet
dependencies)")
with self.lock:
self.buffer.append((client_id, msg_vector, msg_text))
except json.JSONDecodeError:
print("Invalid JSON received")
except ConnectionResetError:
pass
finally:
client_socket.close()
with self.lock:
del self.clients[client_id]
def broadcast(self, message):
with self.lock:
for sock, _ in self.clients.values():
try:
sock.send(message)
except:
pass
def check_buffer(self):
processed = []
with self.lock:
for idx, (client_id, msg_vector, msg_text) in enumerate(self.buffer):
if all(self.vector_clock[cid] >= cnt for cid, cnt in msg_vector.items()):
print(f"Processing buffered message from Client-{client_id}: {msg_text}")
self.vector_clock[client_id] += 1
broadcast_msg = json.dumps({
'vector': self.vector_clock.copy(),
'message': msg_text,
'sender': f"Client-{client_id}"
}).encode()
self.broadcast(broadcast_msg)
processed.append(idx)
for idx in reversed(processed):
del self.buffer[idx]
def run(self):
while True:
client_socket, addr = self.server_socket.accept()
client_id = self.assign_client_id()
with self.lock:
self.clients[client_id] = (client_socket, addr)
client_socket.send(json.dumps({'client_id': client_id}).encode())
print(f"Client-{client_id} connected.")
threading.Thread(target=self.handle_client, args=(client_socket, client_id)).start()
if __name__ == "__main__":
server = CausalOrderingServer()
server.run()
client.py
import threading
import json
from collections import defaultdict
import socket
class CausalOrderingClient:
def __init__(self, server_ip="127.0.0.1", port=23458):
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((server_ip, port))
data = json.loads(self.client_socket.recv(1024).decode())
self.client_id = data['client_id']
self.vector_clock = defaultdict(int)
self.vector_clock[self.client_id] = 0
threading.Thread(target=self.receive_messages, daemon=True).start()
def receive_messages(self):
while True:
try:
data = self.client_socket.recv(1024).decode()
if not data:
break
msg = json.loads(data)
for cid, cnt in msg['vector'].items():
self.vector_clock[int(cid)] = max(self.vector_clock[int(cid)], cnt)
print(f"From {msg['sender']}: {msg['message']}")
except:
break
if __name__ == "__main__":
client = CausalOrderingClient()
while True:
msg = input("Enter message: ")
client.send_message(msg)
OUTPUT:
Server
Client
CONCLUSION:
Thus, through this experiment, we studied and implemented different types of ordering
(absolute ordering, consistent ordering, causal ordering) and their impact on message delivery
in group communication.