Jnsa
Jnsa
Jnsa
LAB MANUAL
Submitted by:
ANAND JHA
2K21/EE/42
Submitted to:
Mr. Preeti Yadav
1
INDEX
2
EXPERIMENT-1
Aim:
Implement concurrent day-time client-server application.
Theory:
This experiment demonstrates a basic client-server interaction using the UDP (User
Datagram Protocol) model. Unlike TCP, which establishes a connection before data transfer,
UDP is connectionless, allowing messages (datagrams) to be sent without prior setup. In
distributed systems, UDP is efficient for low-latency communication where reliability isn't
crucial, as it lacks built-in error correction or message acknowledgment.
Process Flow:
Server binds to a specified address, listens for incoming requests, and responds with
date and time.
Clients send a request and receive a timestamped message from the server, illustrating
asynchronous communication typical of UDP.
CODE:
File: server.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
int main()
{
struct sockaddr_in sa; // Socket address data structure
int sockfd, coontfd; // Source and destination addresses
char str[1025]; // Buffer to hold the out-going stream
time_t tick; // System time data structure
sockfd = socket(AF_INET, SOCK_STREAM, 0); // New socket
3
{
printf("Error in creating socket\n");
exit(0);
}
else
{
printf("Socket Created\n");
}
// Clearing and assigning type and address to the socket
printf("Socket created\n");
bzero(&sa, sizeof(sa));
memset(str, '0', sizeof(str)); // clearing the buffer
sa.sin_family = AF_INET;
sa.sin_port = htons(5600);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
// binding and verifying the socket to address
if (bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
{
printf("Bind Error\n");
}
else
printf("Binded\n");
// starts the server with a max client queue size set as 10
listen(sockfd, 10);
// server run
while (1)
{
coontfd = accept(sockfd, (struct sockaddr *)NULL, NULL); // Accept a request from client
printf("Accepted\n");
tick = time(NULL);
snprintf(str, sizeof(str), "%.24s\r\n", ctime(&tick)); //read sys time and write to buffer
printf("sent\n");
printf("%s\n", str);
write(coontfd, str, strlen(str)); // send buffer to client
}
close(sockfd); // close the socket
return 0;
}
File: client.c
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main()
{
struct sockaddr_in sa; // Socket address data structure
int n, sockfd; // read and source
char buff[1025]; // buffer to store the read stream
4
if (sockfd < 0)
{
printf("Error in creation\n");
exit(0);
}
else
printf("Socket created\n");
// Clearing and assigning type and address to the socket
bzero(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(5600);
// establishing and verifying the connection
if (connect(sockfd, (struct sockaddr_in *)&sa, sizeof(sa)) <
0)
{
printf("Connection failed\n");
exit(0);
}
else
printf("Connection made\n");
// Reading and priting data from the server after verification
if (n = read(sockfd, buff, sizeof(buff)) < 0)
{
printf("Read Error\n");
exit(0);
}
else
{
printf("Read message: %s\n", buff);
printf("%s\n", buff);
printf("Done with connection, exiting\n");
}
close(sockfd); // Closing the socket
return 0;
}
OUTPUT:
Server
Client
5
EXPERIMENT-2
Aim:
Write a program to implement a Lamport Logical clock in a Distributed system
Theory:
Lamport clocks are a logical mechanism for ordering events in distributed systems without
synchronized physical clocks. This system provides a partial ordering of events based on
message exchanges and is crucial in distributed transactions where events need a consistent
timeline.
Algorithm:
Usage: This logical ordering is used in distributed systems requiring consistency, such as
databases or distributed file systems, where conflicts may arise if operations aren’t correctly
ordered.
CODE:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
#define ML 1024
#define MPROC 32
6
}
return sock_id;
}
cl.sin_family = AF_INET;
cl.sin_addr.s_addr = inet_addr("127.0.0.1"); // Use localhost or set appropriate IP
cl.sin_port = htons(to);
sendto(id, (const char *)message, strlen(message), 0, (const struct sockaddr *)&cl, sizeof(cl));
}
7
{
int self = atoi(argv[1]);
int n_proc = atoi(argv[2]);
int phase = atoi(argv[3]);
int procs[MPROC];
int sock_id;
int new_time;
int itr, len, n, start_at;
char buff[ML];
struct sockaddr_in from;
lamport_clock self_clock;
if (start_at == TRUE)
{
printf("Proc %d is starting comms\n", self);
for (itr = 0; itr < n_proc; itr++)
{
printf("Sending to proc: %d\n", procs[itr]);
send_to_id(procs[itr], sock_id, self_clock);
}
}
while (TRUE)
{
printf("\t -------------------------------------------- \n\n");
sleep(1);
tick(&self_clock, phase);
len = sizeof(from);
n = recvfrom(sock_id, (char *)buff, ML, MSG_WAITALL, (struct sockaddr *)&from, &len);
if (n > 0)
{
buff[n] = '\0';
printf("Received time: %s, Self time: %d\n", buff, self_clock.timer);
new_time = atoi(buff);
8
{
printf("Sending time %d to proc %d\n", self_clock.timer, procs[itr]);
send_to_id(procs[itr], sock_id, self_clock);
}
printf("\t -------------------------------------------- \n\n");
}
}
OUTPUT:
Process 1 (Port 5001) Process 2 (Port 5002)
9
Experiment-3
AIM:
Write a program to implement concept of Mutual Exclusion using centralized algorithm.
Thoery:
Mutual exclusion ensures that critical resources in distributed systems are accessed by one
process at a time, avoiding conflicts. The centralized algorithm elects one process as a
coordinator to handle resource requests, manage access control, and prevent race conditions.
Process:
A process requests access from the coordinator. If no other process is in the critical
section, access is granted; otherwise, the request is queued.
After a process completes, it releases control, allowing the next request in the queue
to proceed.
Advantages: Guarantees mutual exclusion and fairness, and ensures no process is left
waiting indefinitely (no starvation).
Drawbacks: The coordinator becomes a single point of failure, which can halt the system if
it crashes, and may also create bottlenecks in high-load scenarios.
CODE:
File: client.c
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
typedef struct resources
{
int A;
char B;
int C;
char D;
} resources;
int main()
{
struct sockaddr_in sa; // Socket address data structure
resources R;
int n, sockfd; // read and source
char buff[1025], obuff[256]; // buffer to store the read stream
10
int snded, rec;
sockfd = socket(PF_INET, SOCK_STREAM, 0); // New socketcreated
// Checking for valid socket
if (sockfd < 0)
{
printf("Error in creation\n");
exit(0);
}
else
printf("Socket created\n");
// Clearing and assigning type and address to the socket
bzero(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(8888);
// establishing and verifying the connection
if (connect(sockfd, (struct sockaddr_in *)&sa, sizeof(sa)) <
0)
{
printf("Connection failed\n");
exit(0);
}
else
printf("Connection made\n");
while (1)
{
snded = write(sockfd, "PING", 5);
if (snded > -1)
printf("SENT PING\n");
rec = read(sockfd, obuff, 256);
obuff[rec] = '\0';
if (strcmp(obuff, "PONG") == 0)
{
usleep(750);
FILE *f;
f = fopen("shared_mem.txt", "r");
fread(&R, sizeof(R), 1, f);
fclose(f);
printf("read %d, %d, %d, %d from server\n", R.A, R.B,
R.C, R.D);
R.A += 1;
R.B += 1;
R.C += 1;
R.D += 1;
f = fopen("shared_mem.txt", "w");
fwrite(&R, sizeof(R), 1, f);
fclose(f);
printf("Got access to CS\n");
snded = write(sockfd, "DONE", 4);
printf("Freeing Lock\n");
break;
}
}
// Reading and priting data from the server after verification
close(sockfd); // Closing the socket
return 0;
}
11
File: controller.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
int main()
{
resources R, temp;
R.A = 1;
R.B = 2;
R.C = 3;
R.D = 4;
FILE *fle;
fle = fopen("shared_mem.txt", "w");
fwrite(&R, sizeof(R), 1, fle);
fclose(fle);
fd_set readfds;
if (sockfd < 0)
{
printf("Error in creating socket\n");
exit(0);
}
else
{
printf("Socket Created\n");
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0)
{
printf("error\n");
12
}
// server run
while (TRUE)
{
// Clearing socket set
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
max_sd = sockfd;
for (i = 0; i < 50; i++)
{
sd = clients[i];
if (sd > 0)
FD_SET(sd, &readfds);
if (sd > max_sd)
max_sd = sd;
}
activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);
if (activity < 0)
printf("Select error\n");
if (FD_ISSET(sockfd, &readfds))
{
if ((new_sock = accept(sockfd, (struct sockaddr *)NULL, NULL)) < 0)
perror("accept");
else
{
printf("New connection, sock fd %d\n", new_sock);
}
13
}
for (i = 0; i < 50; i++)
{
sd = clients[i];
if (FD_ISSET(sd, &readfds))
{
FILE *fle;
fle = fopen("shared_mem.txt", "r");
fread(&temp, sizeof(temp), 1, fle);
fclose(fle);
rec = read(sd, buff, 256);
if (rec == 0)
{
getpeername(sd, (struct sockaddr *)&sa, (socklen_t *)&sa);
printf("%d has disconnected unexpectedly with ip %s and port %d\n", sd, inet_ntoa(sa.sin_addr),
ntohs(sa.sin_port));
printf("recovering data\n");
FILE *fle;
fle = fopen("shared_mem.txt", "w+");
fwrite(&temp, sizeof(temp), 1, fle);
fclose(fle);
close(sd);
clients[i] = 0;
}
else
{
buff[rec] = '\0';
printf("received %s from %d\n", buff, sd);
14
OUTPUT:
15
EXPERIMENT-4
AIM:
Write a program to implement Bully Election algorithm in Distributed systems
Theory:
This algorithm handles coordinator selection within distributed systems. When a coordinator
process fails, the system initiates an election to select a new one with the highest priority.
Steps:
Advantages: Ensures that the highest-priority node assumes control, making it suitable for
leader election in systems with defined hierarchy (e.g., banking or finance systems with
prioritized nodes).
Drawbacks: Requires multiple message exchanges, and the process can be prolonged if
several nodes are involved.
CODE:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MSG_CONFIRM 0
#define TRUE 1
#define FALSE 0
#define ML 1024
#define MPROC 32
16
{
perror("unable to create a socket");
exit(EXIT_FAILURE);
}
cl.sin_family = AF_INET;
cl.sin_addr.s_addr = INADDR_ANY;
cl.sin_port = htons(to);
sendto(id, (const char *)message, strlen(message), MSG_CONFIRM, (const struct sockaddr *)&cl,
sizeof(cl));
}
17
for (itr = 0; itr < num_procs; itr += 1)
if (procs[itr] != self)
send_to_id(procs[itr], id, message);
}
// 1. Create socket
printf("creating a node at %d %d \n", self, start_at);
sock_id = connect_to_port(self);
18
if (!strcmp(buff, "ELECTION"))
{
strcpy(message, "E-ACK"); // send election acknowledgment
sendto(sock_id, (const char *)message, strlen(message), MSG_CONFIRM, (const struct sockaddr
*)&from, sizeof(from));
OUTPUT:
19
EXPERIMENT-5
AIM:
Write a program to implement Ring election algorithm.
Theory:
In the ring election algorithm, processes are arranged in a logical or physical ring. Each
process knows its successor, allowing election messages to circulate around the ring until a
new coordinator is chosen.
Process:
Code:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MSG_CONFIRM 0
#define TRUE 1
#define FALSE 0
#define ML 1024
#define MPROC 32
20
}
21
sprintf(message, "%s", "POLL");
cl.sin_family = AF_INET;
cl.sin_addr.s_addr = INADDR_ANY;
cl.sin_port = htons(to);
sendto(id, (const char *)message, strlen(message), MSG_CONFIRM, (const struct sockaddr *)&cl,
sizeof(cl));
}
// 1. Create socket
printf("creating a node at %d %d \n", self, start_at);
sock_id = connect_to_port(self);
if (strcmp(buff, "POLL") == 0)
{
printf("Received Poll, Sending time to server\n");
send_to_id(server, sock_id, self_clock.timer);
printf("Time sent\n");
}
else
{
new_time = atoi(buff);
printf("Got clock corrections: %d, old time %d\n", new_time, self_clock.timer);
update_clock(&self_clock, new_time);
printf("Updated time, new time: %d\n", self_clock.timer);
exit(EXIT_SUCCESS);
}
printf("\t -------------------------------------------- \n\n");
}
}
22
OUTPUT:
Terminal 1 (Instance 1: self = 8001, server = 8002, phase = 1):
Terminal 1 (Instance 1)
Terminal 2 (Instance 2)
23
EXPERIMENT-6
AIM:
Write a program to implement 2-Phase commit protocol
Theory:
The Two-Phase Commit Protocol is a distributed algorithm used to ensure all nodes in a
system agree to either commit or abort a transaction, achieving consistency across distributed
systems. It’s widely used in databases and distributed transactions.
1. Prepare Phase:
o The coordinator (central controller) sends a "prepare" request to all
participating nodes (or "slaves") after confirming that each node has
completed its portion of the transaction locally.
o Each node responds with either "Ready" (indicating it is ready to commit) or
"Not Ready" (indicating it cannot commit, possibly due to an error or
conflict).
2. Commit/Abort Phase:
o If all nodes respond with "Ready," the coordinator sends a "Global Commit"
message to finalize the transaction across all nodes.
o If any node sends "Not Ready," the coordinator sends a "Global Abort"
message, instructing all nodes to abort the transaction.
o Each node then confirms the commit or abort with an acknowledgment back to
the coordinator.
This protocol is fault-tolerant, ensuring that even if one node fails or votes "Not Ready," no
partial commits occur, maintaining system integrity and preventing inconsistencies.
CODE:
File: server.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MSG_CONFIRM 0
#define TRUE 1
#define FALSE 0
24
#define ML 1024
#define MPROC 32
return sock_id;
}
sendto(from, (const char *)message, strlen(message), MSG_CONFIRM, (const struct sockaddr *)&cl,
sizeof(cl));
}
25
}
}
while (TRUE)
{
sleep(2);
memset(&from, 0, sizeof(from));
n = recvfrom(sock_id, (char *)buffer, ML, MSG_WAITALL, (struct sockaddr *)&from, &len);
buffer[n] = '\0';
printf("Received: %s\n", buffer);
if (strcmp(buffer, "CMOK") == 0)
{
okcnt += 1;
}
else if (strcmp(buffer, "CMNO") == 0)
{
nocnt += 1;
}
if (strcmp(buffer, "DONE") == 0)
{
dncnt += 1;
printf("Clients confirmed commit\n");
if (dncnt == n_procs)
{
printf("All process announced commit action\n");
26
exit(EXIT_SUCCESS);
}
}
}
return 0;
}
File: client.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MSG_CONFIRM 0
#define TRUE 1
#define FALSE 0
#define ML 1024
#define MPROC 32
return sock_id;
}
27
cl.sin_port = htons(to);
sendto(from, (const char *)message, strlen(message), MSG_CONFIRM, (const struct sockaddr *)&cl,
sizeof(cl));
}
while (TRUE)
{
sleep(2);
memset(&from, 0, sizeof(from));
n = recvfrom(sock_id, (char *)buffer, ML, MSG_WAITALL, (struct sockaddr *)&from, &len);
buffer[n] = '\0';
printf("Received: %s\n", buffer);
if (strcmp(buffer, "SCMT") == 0)
{
printf("Sending %s to server\n", action);
send_to_id(server, sock_id, action);
}
else if (strcmp(buffer, "CDON") == 0)
{
printf("Got complete commit, committing to logs\n");
send_to_id(server, sock_id, "DONE");
exit(EXIT_SUCCESS);
}
else if (strcmp(buffer, "CABT") == 0)
{
printf("Got abort commit, deleting updates\n");
send_to_id(server, sock_id, "DONE");
exit(EXIT_FAILURE);
}
}
return 0;
}
28
OUTPUT:
>Coordinator Output
>Client Output:
29
EXPERIMENT-7
AIM:
Write a program to implement 3-Phase commit protocol
Theory:
The 3-Phase Commit Protocol is a distributed transaction protocol designed to ensure that
all participants in a transaction either commit or abort the transaction in a coordinated
manner. It is an extension of the well-known 2-Phase Commit (2PC) protocol, with an
additional phase that reduces the chances of participants getting blocked due to failures.
Key Phases:
1. Pre-Commit Phase:
o The coordinator sends a PREPARE message to all participants, asking them if
they are ready to commit the transaction.
o Participants perform local checks (such as locking resources) and respond with
either an ACK (if ready) or NO (if not ready).
2. Commit Phase:
o If the coordinator receives ACK messages from all participants, it sends a
COMMIT message to all participants, signaling that the transaction can be
committed.
o Participants respond with a COMMIT_ACK to confirm that they have committed
the transaction.
3. Final Commit Phase:
o If any participant fails to acknowledge or there is a failure in communication,
the coordinator sends an ABORT message to all participants, instructing them to
abort the transaction.
o This phase ensures that in case of failure, the system can recover without
leaving transactions in an uncertain state.
Disadvantages:
Complexity: The protocol adds an extra phase, which can increase the complexity of
implementation and message traffic.
Latency: The added communication can result in higher latency for transactions.
30
CODE:
File: coordinator.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main()
{
int sockfd, client_sock, len;
struct sockaddr_in server_addr, client_addr;
char buffer[BUFFER_SIZE];
socklen_t addr_len = sizeof(client_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
31
printf("Received all prepares. Sending commit requests...\n");
File: participant.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main()
{
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
socklen_t addr_len = sizeof(server_addr);
32
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(COORDINATOR_IP);
close(sockfd);
return 0;
}
OUTPUT:
>Coordinator Terminal:
At this point, the coordinator has received PREPARE messages from all three participants and is ready to send
the COMMIT requests to all participants.
33
The coordinator now waits for the COMMIT_ACK responses from all participants.
Participant 1 Terminal:
Participant 2 Terminal:
Participant 3 Terminal:
***
34