Академический Документы
Профессиональный Документы
Культура Документы
DISTRIBUTED SYSTEMS
LAB FILE
CHIRAG YADAV
2K16/CO/84
INDEX
CHIRAG YADAV
2K16/CO/84
INDEX
Aim :
To implement S-DES subkey Generation.
Description:
S-DES is a version of the DES with all parameters significantly reduced, but at the same time
preserving the structure of DES. The goal of S-DES is to allow a beginner to understand the
structure of DES, thus laying a foundation for a thorough study of DES. Its goal is as a teaching
tool in the same spirit as Phan’s.
The encryption algorithm involves five functions: an initial permutation (IP); a complex
function labeled fK, which involves both permutation and substitution operations and depends on
a key input; a simple permutation function that switches (SW) the two halves of the data; the
function fK again; and finally a permutation function that is the inverse of the initial permutation
(IP–1).
Algorithm :
S-DES depends on the use of a 10-bit key shared between the sender and the receiver. From this
key, two 8-bit subkeys are produced for use in particular stages of the encryption and decryption
algorithm. The above figure depicts the stages followed to produce the subkeys. First, permute
the key in the following fashion. Let the 10-bit key be designated as (k1, k2, k3, k4, k5, k6, k7,
k8, k9, k10). Then the permutation P10 is defined as: P10(k1, k2, k3, k4, k5, k6, k7, k8, k9, k10)
= (k3, k5, k2, k7, k4, k10, k1, k9, k8, k6).
The input to the algorithm is an 8-bit block of plaintext, which we first permute using the IP
function: IP(1 2 3 4 5 6 7 8) = (2 6 3 1 4 8 5 7).
The Function fK
The most complex component of S-DES is the function fK, which consists of a combination of
permutation and substitution functions. The functions can be expressed as follows. Let L and R
be the leftmost 4 bits and rightmost 4 bits of the 8-bit input to fK, and let F be a mapping (not
necessarily one to one) from 4-bit strings to 4-bit strings.
The S-box
The first 4 bits (first row of the preceding matrix) are fed into the S-box S0 to produce a 2-bit
output, and the remaining 4 bits (second row) are fed into S1 to produce another 2-bit output.
The function fK only alters the leftmost 4 bits of the input. The switch function (SW)
interchanges the left and right 4 bits so that the second instance of fK operates on a different 4
bits. In this second instance, the E/P, S0, S1, and P4 functions are the same. The key input is K2.
Code:
#include<stdio.h>
int main()
int p10[10]={6,7,8,9,10,1,2,3,4,5};
scanf("%s",input);
input[10]='\0';
//Applying p10...
cnt = p10[i];
temp[i] = input[cnt-1];
temp[i]='\0';
{ printf("%d,",p10[i]); }
puts(temp);
if(i==4)
temp[i]=temp[0];
else
temp[i]=temp[i+1];
if(i==9)
temp[i]=temp[5];
else
temp[i]=temp[i+1];
puts(temp);
{ printf("%d,",p8[i]); }
//Applying p8...
cnt = p8[i];
k1[i] = temp[cnt-1];
puts(k1);
}
Output:
Discussion:
A brute-force attack on simplified DES is certainly feasible. With a 10-bit key, there are only
210
= 1024 possibilities. Given a ciphertext, an attacker can try each possibility and analyze the
result to determine if it is reasonable plaintext.
Let us consider a known plaintext attack in which a single plaintext (p1, p2, p3, p4, p5, p6, p7,
p8) and its ciphertext output (c1, c2, c3, c4, c5, c6, c7, c8) are known and the key (k1, k2, k3, k4,
k5, k6, k7, k8, k9, k10) is unknown. We can therefore express the encryption algorithm as 8
nonlinear equations in 10 unknowns. There are a number of possible solutions, but each of these
could be calculated and then analyzed. Each of the permutations and additions in the algorithm is
a linear G-8 mapping. The nonlinearity comes from the S-boxes.
Simplified DES, developed by Professor Edward Schaefer of Santa Clara University [SCHA96],
is an educational rather than a secure encryption algorithm. It has similar properties and structure
to DES with much smaller parameters.
PROGRAM - 1
Aim :
To implement Caesar Cipher encryption decryption.
Description:
Thus to cipher a given text we need an integer value, known as shift which indicates the
number of position each letter of the text has been moved down.
The encryption can be represented using modular arithmetic by first transforming the letters
Algorithm :
● Traverse the given text one character at a time .
● For each character, transform the given character as per the rule, depending on
whether we’re encrypting or decrypting the text.
● Return the new string generated.
Code:
#include <iostream>
#include <cstring>
int main()
{
std::string input, encoded, decoded;
int key;
std::cout << "Enter the string : ";
std::getline(std::cin, input);
std::cout << "Enter the key : ";
std::cin >> key;
key%=26;
encoded = encoder(input, key);
std::cout << "Encoded string : " << encoded << std::endl;
decoded = decoder(encoded, key);
std::cout << "Decoded string : " << decoded << std::endl;
return 0;
}
Output:
Discussion:
The Caesar cipher can be easily broken even in a ciphertext-only scenario. Two situations can
be considered:
● An attacker knows (or guesses) that some sort of simple substitution cipher has been
used, but not specifically that it is a Caesar scheme;
● An attacker knows that a Caesar cipher is in use, but does not know the shift value.
Aim :
To implement Monoalphabetic encryption decryption.
Description:
A monoalphabetic substitution cipher, also known as a simple substitution cipher, relies on a
fixed replacement structure. That is, the substitution is fixed for each letter of the alphabet.
Thus, if "a" is encrypted to "R", then every time we see the letter "a" in the plaintext, we
Algorithm :
● Traverse the given text one character at a time .
● For each character, transform the given character as per the key, depending on
whether we’re encrypting or decrypting the text.
● Return the new string generated.
Code:
#include <iostream>
#include <cstring>
int enc_array[] = {9, 5, 25, 11, 8, 16, 19, 12, 6, 10, 18, 15, 20, 14, 7, 2, 4, 21, 23, 17, 3, 22,
24, 0, 1, 13};
int dec_array[26];
Output:
Discussion:
One problem with a mono-alphabetic substitution cipher is that an attacker would gain a lot
of information if (s)he gets just one plain-cipher pair. Given few plain-cipher pairs, the
attacker can probably break your full cipher. If you have also data of different size (which
seems to be the case), you should consider taking a family of block ciphers such that you
have a (different) block cipher for each byte-length and encrypt the data with the block cipher
according to its bytelength.
AIM :
To implement Playfair cipher encryption decryption.
DESCRIPTION:
The Playfair cipher was the first practical digraph substitution cipher. The scheme was invented
in 1854 by Charles Wheatstone but was named after Lord Playfair who promoted the use of the
cipher. In playfair cipher unlike traditional cipher we encrypt a pair of alphabets(digraphs)
instead of a single alphabet.
It was used for tactical purposes by British forces in the Second Boer War and in World War I
and for the same purpose by the Australians during World War II. This was because Playfair is
reasonably fast to use and requires no special equipment.
ALGORITHM :
The Algorithm consistes of 2 steps:
1. Generate the key Square(5×5):
○ The key square is a 5×5 grid of alphabets that acts as the key for encrypting the
plaintext. Each of the 25 alphabets must be unique and one letter of the alphabet
(usually J) is omitted from the table (as the table can hold only 25 alphabets). If
the plaintext contains J, then it is replaced by I.
○ The initial alphabets in the key square are the unique alphabets of the key in the
order in which they appear followed by the remaining letters of the alphabet in
order.
2. Algorithm to encrypt the plain text: The plaintext is split into pairs of two letters
(digraphs). If there is an odd number of letters, a Z is added to the last letter.
CODE:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include <cstring>
#define SIZE 30
// Function to convert the string to lowercase
void toLowerCase(char plain[], int ps)
{
int i;
for (i = 0; i < ps; i++) {
if (plain[i] > 64 && plain[i] < 91)
plain[i] += 32;
}
}
// a 26 character hashmap
// to store count of the alphabet
dicty = (int*)calloc(26, sizeof(int));
for (i = 0; i < ks; i++) {
if (key[i] != 'j')
dicty[key[i] - 97] = 2;
}
dicty['j' - 97] = 1;
i = 0;
j = 0;
for (k = 0; k < ks; k++) {
if (dicty[key[k] - 97] == 2) {
dicty[key[k] - 97] -= 1;
keyT[i][j] = key[k];
j++;
if (j == 5) {
i++;
j = 0;
}
}
}
if (a == 'j')
a = 'i';
else if (b == 'j')
b = 'i';
if (a[0] == a[2]) {
str[i] = keyT[a[0]][mod5(a[1] + 1)];
str[i + 1] = keyT[a[0]][mod5(a[3] + 1)];
}
else if (a[1] == a[3]) {
str[i] = keyT[mod5(a[0] + 1)][a[1]];
str[i + 1] = keyT[mod5(a[2] + 1)][a[1]];
}
else {
str[i] = keyT[a[0]][a[3]];
str[i + 1] = keyT[a[2]][a[1]];
}
}
}
// Key
ks = strlen(key);
ks = removeSpaces(key, ks);
toLowerCase(key, ks);
// Plaintext
ps = strlen(str);
toLowerCase(str, ps);
ps = removeSpaces(str, ps);
ps = prepare(str, ps);
// Driver code
int main()
{
char str[SIZE], key[SIZE];
// Key to be encrypted
strcpy(key, "Monarchy");
printf("Key text: %s\n", key);
// Plaintext to be encrypted
strcpy(str, "instruments");
printf("Plain text: %s\n", str);
return 0;
}
OUTPUT:
DISCUSSION:
The Playfair cipher was used mainly to protect important, yet non-critical secrets, as it is quick to
use and requires no special equipment. By the time enemy cryptanalysts could break the code the
information it was protecting would often no longer be relevant.
Aim :
To implement polyalphabetic cipher encryption decryption ( Vigenere Cipher )
Description:
A polyalphabetic cipher is any cipher based on substitution, using multiple substitution
alphabets. Properties of polyalphabetic ciphers are :
The Vigenère cipher is probably the best-known example of a polyalphabetic cipher, though it is
a simplified special case. The Enigma machine is more complex but is still fundamentally a
polyalphabetic substitution cipher.
Algorithm :
The cipher accomplishes encryption using uses a text string (for example, a word) as a key,
which is then used for doing a number of alphabet shifts on the plaintext. Similar to the Caesar
Cipher, but instead of performing a single alphabet shift across the entire plaintext, the Vigenère
cipher uses a key to determine several different shift amounts across the entirety of the message.
Should the key be shorter than the plaintext, it is repeated until the length matches. In this way,
each letter in the plaintext is shifted by the alphabet number of the corresponding letter in the
key.
Expressed mathematically, the encryption of the message at letter *i*, is equal to the alphabetic
value of *i* in the plaintext plus the alphabetic value of the corresponding *i* in the key.
Decryption is the same process reversed, subtracting the key instead of adding to arrive back at
the original, plaintext value.
Code:
#include<bits/stdc++.h>
int x = str.size();
if (x == i)
i = 0;
if (key.size() == str.size())
break;
key.push_back(key[i]);
return key;
string cipher_text;
x += 'A';
cipher_text.push_back(x);
}
return cipher_text;
string orig_text;
x += 'A';
orig_text.push_back(x);
return orig_text;
int main()
cin>>str;
cin>>keyword;
cout<<endl;
return 0;
Output:
Discussion:
The idea behind the Vigenère cipher, like all other polyalphabetic ciphers, is to disguise the
plaintext letter frequency to interfere with a straightforward application of frequency analysis.
For instance, if P is the most frequent letter in a ciphertext whose plaintext is in English, one
might suspect that P corresponds to E since E is the most frequently used letter in English.
However, by using the Vigenère cipher, E can be enciphered as different ciphertext letters at
different points in the message, which defeats simple frequency analysis.
The primary weakness of the Vigenère cipher is the repeating nature of its key. If a cryptanalyst
correctly guesses the key's length, the cipher text can be treated as interwoven Caesar ciphers,
which can easily be broken individually. The Kasiski examination and Friedman test can help to
determine the key length (see below: § Kasiski examination and § Friedman test).
One of the problems with monoalphabetic ciphers is that the letters occur with certain frequency
in a language. This frequency can be graphed for both plaintext letters and the ciphertext letters
of the enciphered message, and, after some analysis, the cipher is relatively easily broken.
PROGRAM - 5
AIM :
To implement hill cipher encryption decryption.
DESCRIPTION:
Hill cipher is a polygraphic substitution cipher based on linear algebra.Each letter is represented
by a number modulo 26. Often the simple scheme A = 0, B = 1, …, Z = 25 is used, but this is not
an essential feature of the cipher. To encrypt a message, each block of n letters (considered as an
n-component vector) is multiplied by an invertible n × n matrix, against modulus 26. To decrypt
the message, each block is multiplied by the inverse of the matrix used for encryption.
The matrix used for encryption is the cipher key, and it should be chosen randomly from the set
of invertible n × n matrices (modulo 26).
ALGORITHM :
To encrypt a message, each block of n letters (considered as an n-component vector) is
multiplied by an invertible n × n matrix, against modulus 26. To decrypt the message, each block
is multiplied by the inverse of the matrix used for encryption.
The matrix used for encryption is the cipher key, and it should be chosen randomly from the set
of invertible n × n matrices (modulo 26). The cipher can, of course, be adapted to an alphabet
with any number of letters; all arithmetic just needs to be done modulo the number of letters
instead of modulo 26.
CODE:
#include <iostream>
using namespace std;
int messageVector[3][1];
int cipherMatrix[3][1];
int main()
{
string message;
cout<<"enter message: ";
cin>>message;
string key;
cout<<"\n enter key: ";
cin>>key;
HillCipher(message, key);
return 0;
}
OUTPUT:
DISCUSSION:
In classical cryptography, the Hill cipher is a polygraphic substitution cipher based on linear
algebra. Invented by Lester S. Hill in 1929, it was the first polygraphic cipher in which it was
practical (though barely) to operate on more than three symbols at once. The following
discussion assumes an elementary knowledge of matrices.
FINDING AND LEARNING
The Hill Cipher was invented by Lester S. Hill in 1929, and like the other Digraphic Ciphers it
acts on groups of letters. Unlike the others though it is extendable to work on different sized
blocks of letters. So, technically it is a polygraphic substitution cipher, as it can work on
digraphs, trigraphs (3 letter blocks) or theoretically any sized blocks.
PROGRAM - 7
Aim :
To implement diffie-hellman key exchange program
Description:
Diffie–Hellman key exchange (DH) is a method of securely exchanging cryptographic keys over
a public channel and was one of the first public-key protocols as originally conceptualized by
Ralph Merkle and named after Whitfield Diffie and Martin Hellman. DH is one of the earliest
practical examples of public key exchange implemented within the field of cryptography.
Also called exponential key exchange, it is a method of digital encryption that uses numbers
raised to specific powers to produce decryption keys on the basis of components that are never
directly transmitted, making the task of a would-be code breaker mathematically overwhelming.
Algorithm :
To implement Diffie-Hellman, the two end users Alice and Bob, while communicating over a
channel they know to be private, mutually agree on positive whole numbers p and q, such that p
is a prime number and q is a generator of p. The generator q is a number that, when raised to
positive whole-number powers less than p, never produces the same result for any two such
whole numbers. The value of p may be large but the value of q is usually small.
Once Alice and Bob have agreed on p and q in private, they choose positive whole-number
personal keys a and b, both less than the prime-number modulus p. Neither user divulges their
personal key to anyone; ideally they memorize these numbers and do not write them down or
store them anywhere. Next, Alice and Bob compute public keys a* and b* based on their
personal keys according to the formulas
a* = qa mod p
and
b* = qb mod p
The two users can share their public keys a* and b* over a communications medium assumed to
be insecure, such as the Internet or a corporate wide area network (WAN). From these public
keys, a number x can be generated by either user on the basis of their own personal keys. Alice
computes x using the formula
x = (b*)a mod p
The value of x turns out to be the same according to either of the above two formulas.
Code:
#include<bits/stdc++.h>
long long int power(long long int a, long long int b, long long int P)
if (b == 1)
return a;
else
int main()
cin>>P;
cin>>G;
cin>>a;
x = power(G, a, P);
cout<<"Enter private key b for Bob : ";
cin>>b;
y = power(G, b, P);
ka = power(y, a, P);
kb = power(x, b, P);
return 0;
Output:
Discussion:
On a mathematical level, the Diffie-Hellman key exchange relies on one-way functions as the
basis for its security. These are calculations which are simple to do one way, but much more
difficult to calculate in reverse.
More specifically, it relies on the Diffie-Hellman problem, which assumes that under the right
parameters, it is infeasible to calculate gab from the separate values of g, ga and gb. There is
currently no publicly known way to easily find gab from the other values, which is why the
Diffie-Hellman key exchange is considered secure, despite the fact that attackers can intercept
the values p, g, A, and B.
AIM
DESCRIPTION
ALGORITHM
#include<iostream>
#include<math.h>
#include<string.h>
#include<stdlib.h>
OUTPUT:
DISCUSSION
RSA derives its security from the difficulty of factoring large integers that are the product of
two large prime numbers. Multiplying these two numbers is easy, but determining the
original prime numbers from the total -- or factoring -- is considered infeasible due to the
time it would take using even today's supercomputers. The public and private key generation
algorithm is the most complex part of RSA cryptography. Two large prime numbers, p and q,
are generated using the Rabin-Miller primality test algorithm. A modulus, n, is calculated by
multiplying p and q. This number is used by both the public and private keys and provides the
link between them. Its length, usually expressed in bits, is called the key length.
FINDING AND LEARNING
RSA security relies on the computational difficulty of factoring large integers. As computing
power increases and more efficient factoring algorithms are discovered, the ability to factor
larger and larger numbers also increases. Encryption strength is directly tied to key size, and
doubling key length can deliver an exponential increase in strength, although it does impair
performance. RSA keys are typically 1024- or 2048-bits long, but experts believe that 1024-
bit keys are no longer fully secure against all attacks. This is why the government and some
industries are moving to a minimum key length of 2048-bits. Barring an unforeseen
breakthrough in quantum computing, it will be many years before longer keys are required.
PROGRAM – 1
AIM:
Implement concurrent day-time client-server application.
DESCRIPTION:
s
There are two major transport layer protocols to communicate between hosts : TCP and UDP.
In UDP, the client does not form a connection with the server like in TCP and instead just sends
a datagram. Similarly, the server need not accept a connection and just waits for datagrams to
arrive. Datagrams upon arrival contain the address of sender which the server uses to send data
to the correct client.
Socket
A socket is a combination of IP address and
port on one system. On each system a socket
exists for a process interacting with the socket
on other system over the network. A
combination of local socket and the socket at
the remote system is also known a ‘Four tuple’
or ‘4-tuple’. Each connection between two
processes running at different systems can be
uniquely identified through their 4-tuple.
Function Descriptions
socket()
Creates an UN-named socket inside the kernel and returns an integer known as
socket descriptor. This function takes domain/family as its first argument. For
Internet family of ipv4 addresses we use AF_INET. The second argument
‘SOCK_STREAM’ specifies that the transport layer protocol that we want
should be reliable i.e. It should have acknowledgement techniques. The third
argument is generally left zero to let the kernel decide the default protocol to
use for this connection. For connection oriented reliable connections, the default
protocol used is TCP.
bind()
Assigns the details specified in the structure ‘serv_addr’ to the socket created in
the step above. The details include, the family/domain, the interface to listen
on(in case the system has multiple interfaces to network) and the port on which
the server will wait for the client requests to come.
listen()
With second argument as ’10’ specifies maximum number of client connections
that server will queue for this listening socket. After the call to listen(), this
socket becomes a fully functional listening socket.
accept()
The server is put to sleep and when for an incoming client request, the three-
way TCP handshake is complete, the function accept () wakes up and returns
the socket descriptor representing the client socket. Accept() is run in an infinite
loop so that the server is always running and the delay or sleep of 1 sec ensures
that this server does not eat up all your CPU processing. As soon as server gets
a request from client, it prepares the date and time and writes on the client socket
through the descriptor returned by accept().
ALGORITHM:
Server
1. Create UDP socket
2. Bind socket to address
3. Wait for datagram from client process and reply to client request
4. Repeat while server is active
Client
1. Create UDP socket
2. Send request to server
3. Wait for datagram from server
4. Process and reply from server
5. Close socket and exit
CODE:
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;
printf("Socket created\n");
bzero(&sa, sizeof(sa));
memset(str, '0', sizeof(str));
sa.sin_family = AF_INET;
sa.sin_port = htons(5600);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
listen(sockfd, 10);
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
}
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;
int n, sockfd;
char buff[1025];
if (sockfd < 0)
{
printf("Error in creation\n");
exit(0);
}
else
printf("Socket created\n");
bzero(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(5600);
OUTPUT:
DISCUSSION:
If we are creating a connection between client and server using TCP then it has few functionality
like, TCP is suited for applications that require high reliability, and transmission time is relatively
less critical. It is used by other protocols like HTTP, HTTPs, FTP, SMTP, Telnet. TCP rearranges
data packets in the order specified. There is absolute guarantee that the data transferred remains
intact and arrives in the same order in which it was sent. TCP does Flow Control and requires
three packets to set up a socket connection, before any user data can be sent. TCP handles
reliability and congestion control. It also does error checking and error recovery. Erroneous
packets are retransmitted from the source to the destination.
AIM :
Write a program to implement Lamport Logical clock in a distributed system
DESCRIPTION:
A Lamport logical clock is an incrementing counter maintained in each process. Conceptually,
this logical clock can be thought of as a clock that only has meaning in relation to messages
moving between processes. When a process receives a message, it resynchronizes its logical
clock with that sender (causality).
ALOGRITHM :
• All the process counters start with value 0.
• A process increments its counter for each event (internal event, message sending,
message receiving) in that process.
• When a process sends a message, it includes its (incremented) counter value with the
message.
• On receiving a message, the counter of the recipient is updated to the greater of its
current counter and the timestamp in the received message, and then incremented by one.
CODE:
#include<stdio.h>
int max1(int a, int b) //to find the maximum timestamp between two events
if (a>b)
return a;
else
return b;
int main()
{
int i,j,k,p1[20],p2[20],e1,e2,dep[20][20];
scanf("%d %d",&e1,&e2);
for(i=0;i<e1;i++)
p1[i]=i+1;
for(i=0;i<e2;i++)
p2[i]=i+1;
printf("\t enter 1 if e1->e2 \n\t enter -1, if e2->e1 \n\t else enter 0 \n\n");
for(i=0;i<e2;i++)
printf("\te2%d",i+1);
for(i=0;i<e1;i++)
for(j=0;j<e2;j++)
scanf("%d",&dep[i][j]);
for(i=0;i<e1;i++)
for(j=0;j<e2;j++)
{
if(dep[i][j]==1) //change the timestamp if dependency exist
{ p2[j]=max1(p2[j],p1[i]+1);
for(k=j;k<e2;k++)
p2[k+1]=p2[k]+1;
p1[i]=max1(p1[i],p2[j]+1);
for(k=i;k<e1;k++)
p2[k+1]=p1[k]+1;
for(i=0;i<e1;i++)
printf("%d",p1[i]);
printf("\n P2 : ");
for(j=0;j<e2;j++)
printf("%d",p2[j]);
return 0 ;
OUTPUT:
DISCUSSION:
One of the shortcomings of Lamport Timestamps is rooted in the fact that they only partially
order events (as opposed to total order). Partial order indicates that not every pair of events need
be comparable. If two events can’t be compared, we call these events concurrent. The problem
with Lamport Timestamps is that they can’t tell if events are concurrent or not. This problem is
solved by Vector Clocks.
AIM :
To implement bi-directional ring election Algorithm.
DESCRIPTION :
Another election algorithm is based on the use of a ring, but without a token. We assume that
the processes are physically or logically ordered, so that each process knows who its
successor is. When any process notices that the coordinator is not functioning, it builds an
ELECTION message containing its own process number and sends the message to its
successor. If the successor is down, the sender skips over the successor and goes to the next
member along the ring, or the one after that, until a running process is located. At each step,
the sender adds its own process number to the list in the message. Eventually, the message
gets back to the process that started it all. That process recognizes this event when it receives
an incoming message containing its own process number. At that point, the message type is
changed to COORDINATOR and circulated once again, this time to inform everyone else
who the coordinator is (the list member with the highest number) and who the members of
the new ring are. When this message has circulated once, it is removed and everyone goes
back to work.
CODE :
#include<string.h>
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
struct rr
{
int index;
int id;
int f;
char state[10];
}proc[10];
int i,j,k,m,n;
int main(){
int temp;
char str[10];
cout<<"enter the number of process\n";
cin>>n;
for(i=0;i<n;i++){
cout<<"enter id of process\t";
cin>>proc[i].id;
strcpy(proc[i].state,"active");
proc[i].f=0;
}
// sorting
for(i=0;i<n-1;i++){
for(j=0;j<n-1;j++){
if(proc[j].id>proc[j+1].id){
temp=proc[j].id;
proc[j].id=proc[j+1].id;
proc[j+1].id=temp;
}
}
}
for(i=0;i<n;i++)
printf("[%d] %d\t",i,proc[i].id);
int init;
int ch;
int temp1;
int temp2;
int arr[10];
strcpy(proc[n-1].state,"inactive");
cout<<"\nprocess "<<proc[n-1].id<<" select as coordinator";
while(1) {
cout<<"\n1)election 2)quit\n";
scanf("%d",&ch);
for(i=0;i<n;i++){
proc[i].f=0;
}
switch(ch)
{
case 1: cout<<"\nenter the process Number who intialised election";
scanf("%d",&init);
temp2=init;
temp1=init+1;
i=0;
while(temp2!=temp1){
if(strcmp(proc[temp1].state,"active")==0 && proc[temp1].f==0 ){
cout<<"process "<<proc[init].id<<" send message to
"<<proc[temp1].id<<"\n";
proc[temp1].f=1;
init=temp1;
arr[i]=proc[temp1].id;
i++;
}
if(temp1==n)
temp1=0;
else
temp1++;
}
cout<<"process "<<proc[init].id<<" send message to "<<proc[temp1].id<<"\n";
arr[i]=proc[temp1].id;
i++;
int max=-1;
for(j=0;j<i;j++){
if(max<arr[j])
max=arr[j];
}
cout<<"\nprocess "<<max<<" select as coordinator";
for(i=0;i<n;i++){
if(proc[i].id==max){
strcpy(proc[i].state,"inactive");
// cout<<"\n"<<i<<" "<<proc[i].id<<"deactivate\n";
}
}
break;
break;
}
}
return 0;
}
OUTPUT:
DISCUSSION :
Eventually, the message gets back to the process that started it all. That process recognizes
this event when it receives an incoming message containing its own process number. At that
point, the message type is changed to COORDINATOR and circulated once again, this time
to inform everyone else who the coordinator is (the list member with the highest number) and
who the members of the new ring are. When this message has circulated once, it is removed
and everyone goes back to work.
AIM :
Write a program to implement Bully Election algorithm in a distributed system
DESCRIPTION:
Election algorithms choose a process from group of processors to act as a coordinator. If the
coordinator process crashes due to some reasons, then a new coordinator is elected on other
processor. Election algorithm basically determines where a new copy of coordinator should
be restarted. Bully algorithm applies to system where every process can send a message to
every other process in the system.
ALOGRITHM :
Suppose process P sends a message to the coordinator.
● If coordinator does not respond to it within a time interval T, then it is assumed that
coordinator has failed.
● Now process P sends election message to every process with high priority number.
● It waits for responses, if no one responds for time interval T then process P elects
itself as a coordinator.
● Then it sends a message to all lower priority number processes that it is elected as
their new coordinator.
● However, if an answer is received within time T from any other process Q,
● (I) Process P again waits for time interval T’ to receive another message from Q that it
has been elected as coordinator.
● (II) If Q doesn’t responds within time interval T’ then it is assumed to have failed and
algorithm is restarted.
CODE:
#include<bits/stdc++.h>
#include<stdio.h>
#include<stdlib.h>
struct process {
int no;
int priority;
int active;
};
struct priority {
int pri;
proc *pp;
};
proc *p1;
p1 = head;
if (p1->active == 1) {
if (head1 == NULL) {
head1->pri = p1->priority;
head1->next = NULL;
head1->pp = p1;
p2 = head1;
} else {
p3 = (pri*) malloc(sizeof(pri));
p3->pri = p1->priority;
p3->pp = p1;
p3->next = NULL;
p2->next = p3;
p2 = p2->next;
p1 = p1->next;
} else
p1 = p1->next;
} //end while
p3 = (pri*) malloc(sizeof(pri));
p3->pri = p1->priority;
p3->pp = p1;
p3->next = NULL;
p2->next = p3;
p2 = p2->next;
p3 = head1;
return head1;
} //end find_priority()
int find_max_priority(pri *head) {
pri *p1;
int i = 0;
p1 = head;
max = p1->pri;
i = p1->pp->no;
p1 = p1->next;
return i;
void bully() {
proc *head;
proc *p1;
proc *p2;
char ch;
head = p1 = p2 = NULL;
scanf("%d", &n);
scanf("%d", &pr);
scanf("%d", &a);
if (head == NULL) {
if (head == NULL) {
exit(0);
head->no = i + 1;
head->priority = pr;
head->active = a;
head->next = head;
p1 = head;
} else {
p2 = (proc*) malloc(sizeof(proc));
if (p2 == NULL) {
printf("\nMemory cannot be allocated");
exit(0);
p2->no = i + 1;
p2->priority = pr;
p2->active = a;
p1->next = p2;
p2->next = head;
p1 = p2;
} //end for
scanf("%d", &pid);
p2 = head;
if (p2->no == pid) {
p2 = p2->next;
break;
p2 = p2->next;
p2 = p2->next;
printf("%d", p2->no);
p2 = head;
max = 0;
while (1) {
max = p2->no;
p2 = p2->next;
if (p2 == head)
break;
int main() {
bully();
return 0;
}
OUTPUT:
DISCUSSION:
In distributed computing, the bully algorithm is a method for dynamically electing a
coordinator or leader from a group of distributed computer processes. The process with the
highest process ID number from amongst the non-failed processes is selected as the
coordinator.
The algorithm assumes that:
● the system is synchronous.
● processes may fail at any time, including during execution of the algorithm.
● a process fails by stopping and returns from failure by restarting.
AIM
DESCRIPTION
ALGORITHM
//APIs
void CS_RequestCriticalSection( int processId, int *clock );
void CS_ReceivedRequest( int processId, int reqProcessId, int clock);
void CS_ReceivedReply( int processId, int fromProcessId );
sleep(2);
//Process 1 receives request from 0
CS_ReceivedRequest( 1, 0, timeStamp0 );
sleep(2);
//Process 0 receives reply from 1
CS_ReceivedReply( 0, 1);
sleep(2);
//Process 1 receives reply from 2
CS_ReceivedReply( 1, 2 );
sleep(2);
//Process 0 receives reply from 2
CS_ReceivedReply( 0, 2 );
sleep(2);
//Process 1 receives reply from 0
CS_ReceivedReply( 1, 0 );
sleep(5);
}
void CS_RequestCriticalSection( int processId, int *clock ){
GetTimestamp( clock );
//Update requesting process's clock
processes[ processId ].clock[ processId ] = *clock;
printf( "Process [%d] at Timestamp [%d] Broadcasting REQUEST message\n", processId,
*clock );
}
void CS_ReceivedRequest( int processId, int reqProcessId, int clock){
printf("Process [%d] received REQUEST from Process [%d] with Timestamp [%d]\n",
processId, reqProcessId, clock );
//Updae clock
processes[ processId ].clock[ reqProcessId ] = clock;
//Process Request
ProcessRequest( processId, reqProcessId );
}
void CS_ReceivedReply( int processId, int fromProcessId ){
int exe_cs = 1;
//Set Reply flag
processes[ processId ].reply[ fromProcessId ] = 1;
printf("Process [%d] received REPLY from process [%d]\n", processId, fromProcessId);
//Check reply from all the other processes
for( int i = 0; i < NUM_PROCESS; i++ ) {
if( ( i != processId ) && ( processes[ processId ].reply[ i ] != 1 ) ){
exe_cs = 0;
}
}
if( exe_cs == 1 ){
printf("Process [%d] received REPLY from All the processes\n", processId);
ExecuteCriticalSection( processId );
}
}
static ProcessRequest( int processId, int reqProcessId ){
if( ( processes[ processId ].cs_flag == 1 ) || (processes[ processId ].clock[ processId ] != 0 )
){
if( processes[ processId ].clock[ reqProcessId ] < processes[ processId ].clock[
processId ] ){
//Send REPLY
SendReply( processId, reqProcessId);
}
else {
//Set request deffered flag for requesting process, at receiving process
processes[ processId ].RD[ reqProcessId ] = 1;
printf( "Process [%d] REQUEST from Process [%d] is DEFFERED\n", processId,
reqProcessId ); } } }
static void SendReply( int processId, int reqProcessId ) {
/* Reset requesting process's clock and RD flag at process receiving process */
processes[ processId ].clock[ reqProcessId ] = 0;
processes[ processId ].RD[ reqProcessId ] = 0;
printf( "Process [%d] sending REPLY to Process [%d]\n", processId, reqProcessId );
}
static void ExecuteCriticalSection( int processId ){
//Entering critical section
processes[ processId ].cs_flag = 1;
printf( "Process [%d] enters critical section\n", processId );
//Executing critical section
sleep(1);
printf( "Process [%d] is executing critical section\n", processId );
sleep(1);
//Exiting critical section
printf( "Process [%d] exits critical section\n", processId );
processes[ processId ].cs_flag = 0;
//Send reply to deffered processes
for( int i = 0; i < NUM_PROCESS; i++ ){
if( ( i != processId ) && ( processes[ processId ].RD[i] != 0 ) ){
SendReply( processId, processes[ processId ].RD[i]);
processes[ processId ].RD[i] = 0;
processes[ processId ].reply[ i ] = 0;
}}
}
static void GetTimestamp(int *clock) {
time_t t = time(NULL);
struct tm tm = *localtime(&t);
*clock = tm.tm_hour * 60 * 60 + tm.tm_min * 60 + tm.tm_sec; //In seconds
}
OUTPUT:
DISCUSSION
Message Complexity:
Ricart–Agrawala algorithm requires invocation of 2(N – 1) messages per critical section
execution. These 2(N – 1) messages involves
● (N – 1) request messages
● (N – 1) reply messages