0% found this document useful (0 votes)
5 views9 pages

DC Exp3

The document outlines an experiment focused on studying and implementing group communication in distributed systems, detailing various communication types such as one-to-many, many-to-one, and many-to-many. It includes code examples for absolute, consistent, and causal ordering mechanisms, demonstrating how messages are handled and delivered among multiple clients. The conclusion emphasizes the importance of these ordering types in ensuring effective message delivery within group communication.

Uploaded by

Mithali
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views9 pages

DC Exp3

The document outlines an experiment focused on studying and implementing group communication in distributed systems, detailing various communication types such as one-to-many, many-to-one, and many-to-many. It includes code examples for absolute, consistent, and causal ordering mechanisms, demonstrating how messages are handled and delivered among multiple clients. The conclusion emphasizes the importance of these ordering types in ensuring effective message delivery within group communication.

Uploaded by

Mithali
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

DEPARTMENT OF COMPUTER ENGINEERING

DATE:
ROLL NO: B803
EXPERIMENT NO. 03

AIM: To study and implement Group Communication.

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.

TYPES OF GROUP COMMUNICATION:


1. One-to-Many Communication (Multicast/Broadcast)
• A single sender transmits messages to multiple receivers. Broadcast sends messages to all
network nodes, while multicast targets a specific group.
• Use Case: A server manager managing multiple servers can multicast a message requesting
available servers to volunteer for a task. The first server that responds is selected, avoiding
the need to track available servers individually.
Service discovery: A system can broadcast an inquiry message to locate a service provider
in the network.
2. Many-to-One Communication
• Multiple senders send messages to a single receiver. The receiver can be selective
(expecting messages from a specific sender) or nonselective (accepting from any sender in
a group).
• Use Case: A buffer process can receive messages from multiple producer processes when
it has space and from consumer processes when it has data available, ensuring efficient
resource management.
Data aggregation: Sensors in an IoT network send temperature readings to a central
monitoring system for analysis.
3. Many-to-Many Communication
• Multiple senders communicate with multiple receivers, combining elements of both
previous types. This requires message ordering mechanisms to ensure all receivers process
messages consistently.
• Use Case: Database replication: Updates from multiple clients must be delivered in the
same order to all database replicas to maintain consistency.
Collaborative applications: A shared document editing system ensures all users see changes
in the same sequence, preventing conflicts.
TYPES OF MANY-TO-MANY COMMUNICATION:
1. Absolute Ordering
• Ensures all messages are delivered to all
receivers in the exact order they were sent.
• Implementation: Uses global timestamps
synchronized across all machines.
Messages are stored in a queue and delivered
in fixed time intervals to maintain order.
• Use Case: Stock trading systems require
messages about stock price updates to be
received in the precise order they were issued
to maintain consistency across all trading
platforms.

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 broadcast(self, message, sender_socket):


self.message_counter += 1
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
client_id = self.client_ids.get(sender_socket, "Unknown Client")
ordered_message = f"{self.message_counter} [{timestamp}] from {client_id}: {message}"
for client in self.clients:
client.send(ordered_message.encode())

def handle_client(self, client_socket, client_id):


self.client_ids[client_socket] = client_id
while True:
try:
message = client_socket.recv(1024).decode()
if not message:
break
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] Received from {client_id}: {message}")
self.broadcast(message, client_socket)
except:
break
client_socket.close()

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

def send_message(self, message):


self.client_socket.send(message.encode())

if __name__ == "__main__":
client = AbsoluteOrderingClient()
while True:
msg = input("Enter message: ")
client.send_message(msg)

OUTPUT:
Server

Client 1 and Client 2


Part B: Consistent Ordering
server.py
import socket
import threading
from datetime import datetime

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 broadcast(self, message, sender_id):


timestamp = datetime.now().strftime("%H:%M:%S")
formatted_message = f"[{timestamp}] {sender_id}: {message}"
for client in self.clients:
client.send(formatted_message.encode())

def handle_client(self, client_socket, client_id):


self.client_ids[client_socket] = client_id
while True:
try:
message = client_socket.recv(1024).decode()
if not message:
break
print(f"Received from {client_id}: {message}")
self.broadcast(message, client_id)
except:
break
client_socket.close()

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

def send_message(self, message):


self.client_socket.send(message.encode())

if __name__ == "__main__":
client = ConsistentOrderingClient()
while True:
msg = input("Enter message: ")
client.send_message(msg)

OUTPUT:
Server

Client1 and Client2

Part C: Casual Ordering


server.py
import socket
import threading
import json
from collections import defaultdict

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

def handle_client(self, client_socket, client_id):


try:
while True:
data = client_socket.recv(1024).decode()
if not data:
break
try:
msg = json.loads(data)
msg_vector = {int(k): v for k, v in msg['vector'].items()}
msg_text = msg['message']

print(f"Received from Client-{client_id}: {msg_text} with vector {msg_vector}")

# Check if causal dependencies are satisfied


can_process = all(self.vector_clock[cid] >= cnt for cid, cnt in msg_vector.items())

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

def send_message(self, message_text):


msg = {
'vector': dict(self.vector_clock),
'message': message_text
}
print(f"Sending message: {message_text} with vector {self.vector_clock}")
self.client_socket.send(json.dumps(msg).encode())
self.vector_clock[self.client_id] += 1 # Increment vector clock after sending

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.

You might also like