Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 30

COMPUTER NETWORK

PRACTICAL

Prepared By:
Kaushik Mazumder – ECB19025
Experiment 1

Aim: Design ASCII encoder-decoder using C/C++ programming

(i) We are studying Computer Network.

Theory: Data conversion has always been a widely used application and one
among them can be “conversion of a string to its binary equivalent”. The idea
is to first calculate the length of the string as n and then run a loop n times. In each
iteration store ASCII value of character in variable val and then convert it into
binary number and store result in array finally print the array in reverse order.

Program and Output:

#include <bits/stdc++.h>
using namespace std;

void strToBin(int c, string &k)


{
if (c == 0)
{
k.push_back('0');
return;
}
if (c % 2)
k.push_back('1');
else
k.push_back('0');
strToBin(c / 2, k);
}

string binToStr(string k){


double power = 7;
string res = "";
int total = 0;
for(int i = 0; i<k.length(); i++){
if(k[i] == '1') total+=pow(2.0, power);
if(power > 0) power--;
else{
res+=(char)total;
power = 7;
total = 0;
}
}
return res;
}
int main()
{
string s;
cout << "Enter input string : \n";
getline(cin, s);
cout << "The binary equivalent of " << s << " is :" << endl;
string k;

for (int i = 0; i < s.size(); i++)


{
k = "";
if(s[i] == ' ') cout << "00100000";
else{
strToBin(s[i], k);
reverse(k.begin(), k.end());
cout << k;
}

cout << endl << "Enter the binary to be decoded to string : \n";
cin >> k;
cout << binToStr(k);
return 0;
}

Output:
Experiment 2:

Aim: Design Asynchronous transmitter and receiver using C/C++ code:

"I am student of TU"

Theory: Asynchronous Transmission is a mode of serial transmission for modems


and other telecommunication devices in which the data is transmitted as a
continuous stream of bytes separated by start and stop bits.

In asynchronous communication, only about 80 percent of the transmitted bits


actually contain data, while the other 20 percent contain signaling information in
the form of start and stop bits. Each data frame starts with a start bit and ends with
a stop bit, with data bits in between. When the receiving station receives a start bit,
it knows that pure data will follow. When a stop bit is received, it knows the data
frame has ended and waits for the next one.

Program:

#include <bits/stdc++.h>
using namespace std;

// utility function

string strToBinary(string s)
{
int n = s.length();
string bin2 = "";
for (int i = 0; i < n; i++)
{

// convert each char to


// ASCII value

int val = int(s[i]);

// Convert ASCII value to binary


string bin = "";
while (val> 0)
{
if(val % 2 == 0)
bin.push_back('0');
else
bin.push_back('1');
val /= 2;
}
bin.append(" 0");
reverse(bin.begin(), bin.end());
string con = " 1";
bin.append(con);
bin2.append(bin);
bin2.append(" ");
cout<< bin << " ";
}
return bin2;
}

//Receiver

// A quick way to split strings separated via spaces.

void simple_tokenizer(string s)
{
stringstream ss (s);
string word;
string str = "";
while (ss>> word) {
if(word != "0" && word != "11")
{//cout<<"\n" << word ;
int w = std::bitset<7>(word).to_ulong();
char r = static_cast<char>(w);
str += r;
}
}
cout<<"\n"<< "Recieved: "<<str;
}
void Reciever(string x)
{
//token =
simple_tokenizer(x);
//cout<<"\n"<<token
}
// driver code
int main()
{
string s = "I am a student of TU";
string x = strToBinary(s);
cout<<"\n"<<x;
Reciever(x);
return 0;
}

Output:
Experiment 3:

Aim: Design Synchronous transmitter and receiver using C/C++ code:

"I am student of TU"

Theory: Synchronous transmission is transmission of signals in a fixed interval


based on a predefined clocking signal and is meant for constant and reliable
transmission of time-sensitive data such as VoIP and audio/video streaming.

This method of transmission is used when large amounts of data need to be


transferred quickly since data is transferred in large blocks instead of individual
characters. The data blocks are spaced and grouped in regular intervals and
preceded by synchronous characters that a remote device decode and use to
synchronize the connection between the endpoints.

After synchronization is complete, the transmission can begin.

Program:

#include <bits/stdc++.h>
using namespace std;

// utility function

string strToBinary(string s)

int n = s.length();
string bin2 = "";

for (int i = 0; i < n; i++)


{

// convert each char to

// ASCII value
int val = int(s[i]);

string bin = "";

// Convert ASCII value to binary


while (val > 0)
{

if(val % 2 == 0)
bin.push_back('0');
else

bin.push_back('1');
val /= 2;
}
bin.append("0"); //For 8 bit frame
reverse(bin.begin(), bin.end());
if(bin.length()<8)

{
bin = "0" + bin;

bin2.append(bin);

cout <<"\n11111111 "<<"1111111 "<< bin2<<" 1111111"<<" 11111110";

return bin2;

//Reciever

string Reciever(string s)

int n = s.length();
string k = "";
for(int i = 0; i<n ;i+=8)

{
string str = "";

for(int j = i+1; j<i+8; j++)


{

str += s[j];
}

//cout<<"\n "<<str;

int w = std::bitset<7>(str).to_ulong();
char r = static_cast<char>(w);
k += r;

cout<<"\n"<<k;
return k;

// driver code
int main()
{

string s = "I am student of TU";


cout<<"\n Transmitted: ";
string x = strToBinary(s);

cout<<"\n Recieved: ";


string y = Reciever(x);
return0

Output:
Experiment 6 :

Aim: Implement CRC using C/C++.

Theory: Cyclic Redundancy Check is the most powerful and easy to implement
technique. Unlike checksum scheme, which is based on addition, CRC is based on
binary division.
In CRC, a sequence of redundant bits, called cyclic redundancy check bits, are
appended to the end of data unit so that the resulting data unit becomes exactly
divisible by a second, predetermined binary number. At the destination, the
incoming data unit is divided by the same number. If at this step there is no
remainder, the data unit is assumed to be correct and is therefore accepted. A
remainder indicates that the data unit has been damaged in transit and therefore
must be rejected.

Program:

#include <stdio.h>

#include <iostream>

using namespace std;

struct HDLC // this structure will store valid inputs

{ char validInput[64] ;
};

void DisplayInfoSent( struct HDLC fa_HDLC, int fcounter )


{
int i = 1 ;
cout<<"\nThe end of the end Flag has been detected."<<endl ;

cout<< "\nThe information sent was:\n"<<endl ;

for ( i ; i < fcounter ; i++ )

{ cout<< fa_HDLC.validInput[i]<<endl ;

int main ()

struct HDLC a_HDLC ;

char input ;

int flag = 0 ; // Integer for detecting two flags, (flag =1) first flag detected, (flag= 2)
end flag found.

int counter = 1 ; // Counts the number of characters entered in a message.

int j=0; // Flag state tracker, 0= no part of flag detected

cout<<"This program exits upon entering '!'\n"<<endl;

while ( input != '!' && flag != 2 && counter<64)

{ if (j == 0 ) // Check to see if part of flag has been detected or not.

{ input = getchar() ;

if ( input == '0' )

{ input = getchar() ; // State1 detected. j+


+;

if ( input == '1' )

{ input = getchar() ; // State2 detected. j+

+;

if ( input == '1' )

{ input = getchar() ; // State3 detected. j+

+;

if ( input == '1' )

{ input = getchar() ; // State4 detected. j+

+;

if ( input == '1' )

{ input = getchar() ; // State5 detected. j+

+;

if ( input == '1' )

{ input = getchar() ; // State6 detected. j+

+;

if ( input == '1' )

{ input = getchar() ; // State7 detected. j+

+;

if ( input == '0' )

{// State8 detected.

if(flag == 0)
{

cout<<"\nThe Flag has been detected\n\n"<<endl;

j=0;

flag++ ;

input = ' ' ;// For clearing buffer after flag

}//End flag detected 8/8

}//End flag detected 7/8

}//End flag detected 6/8

}//End flag detected 5/8

}//End flag detected 4/8

}//End flag detected 3/8

}//End flag detected 2/8

}//End flag detected 1/8

if ( flag == 1 )//First flag detected

a_HDLC.validInput[ counter ] = input ; // Save input until last end flag

counter++ ;

}// End if

}// End wile loop

if( input == '!' )


{ cout<<"\nThe exit command was used."<<endl;

}// End if

else

{ DisplayInfoSent( a_HDLC , counter );

}// End else

return 0;

Output:
Experiment 4:

Aim: Generate HDLC frame using C/C++.

Theory: High-Level Data Link Control (HDLC) is a bit-oriented code-transparent


synchronous data link layer protocol developed by the International Organization
for Standardization (ISO).

HDLC frames can be transmitted over synchronous or asynchronous serial


communication links. Those links have no mechanism to mark the beginning or
end of a frame, so the beginning and end of each frame has to be identified. This is
done by using a unique sequence of bits as a frame delimiter, or flag, and encoding
the data to ensure that the flag sequence is never seen inside a frame. Each frame
begins and ends with a frame delimiter. A frame delimiter at the end of a frame
may also mark the start of the next frame.

On both synchronous and asynchronous links, the flag sequence is binary


"01111110", or hexadecimal 0x7E, but the details are quite different.

Program :

#include<bits/stdc++.h>
using namespace std;
// Finds XOR of 'a' and 'b' (both of same length)
string xor1(string a, string b)
{

string result = "";


int n = b.length();
// Traverse all bits,

// if bits are same, then XOR is 0, else 1


for(int i = 1; i < n; i++)
{

if (a[i] == b[i])

result += "0";

else

result += "1";
}

return
result;

// Performs Modulo-2 division

string mod2div(string divident, string divisor)

// Number of bits to be XORed at a time.


int pick = divisor.length();
string tmp = divident.substr(0, pick);
int n = divident.length();
while (pick < n)

if (tmp[0] == '1')

// Replace divident by the result of XOR and pull 1 bit down


tmp = xor1(divisor, tmp) + divident[pick];

else

tmp = xor1(std::string(pick, '0'), tmp) +


divident[pick];
// Increment pick to move further
pick += 1;
}

if (tmp[0] == '1')

tmp = xor1(divisor, tmp);

else

tmp = xor1(std::string(pick, '0'), tmp);

return tmp;

void encodeData(string data, string key)

int l_key = key.length();

// Appends n-1 zeroes at end of data

string appended_data = (data + std::string(l_key - 1, '0'));


string remainder = mod2div(appended_data, key);
// Append remainder in the original data
string codeword = data + remainder;
cout << "FCS : " << remainder << "\n";
cout << "Transmitted Bits (Data + Remainder) :" << codeword << "\n";

int main()

string data = "10100011010111001";


string key = "11010010011";

cout << "Result:-" << endl;


encodeData(data, key);
return 0;
}

Output :
Experiment 5:

Aim: Implement two dimensional parity check using C/C++.

Theory: Performance can be improved by using two-dimensional parity check,


which organizes the block of bits in the form of a table. Parity check bits are
calculated for each row, which is equivalent to a simple parity check bit. Parity
check bits are also calculated for all columns then both are sent along with the
data. At the receiving end these are compared with the parity bits calculated on the
received data.

Two-dimension Parity Checking

Two- Dimension Parity Checking increases the likelihood of detecting burst


errors. As we have shown in Fig that a 2-D Parity check of n bits can detect a burst
error of n bits. A burst error of more than n bits is also detected by 2-D Parity
check with a high-probability. There is, however, one pattern of error that remains
elusive. If two bits in one data unit are damaged and two bits in exactly same
position in another data unit are also damaged, the 2-D Parity check checker will
not detect an error.
Example, if two data units: 11001100 and 10101100. If first and second from last
bits in each of them is changed, making the data units as 01001110 and 00101110,
the error cannot be detected by 2-D Parity check.
Program:

#include <iostream>
#include <string.h>
#define MAX 100
#define PARITY 100

using namespace std;

int main() {
int i,j,seg,flag=0;
char arr[MAX],vrc[PARITY],lrc[PARITY];

cout<<"Enter the bit value:";


cin>>arr;

for(i=2;i<strlen(arr);i++){
if(strlen(arr)%i==0){
flag=1;
break;
}else{
flag=0;
}
}
if(flag==1){
seg=strlen(arr)/i;
}else{
seg=strlen(arr);
}

for(i=0;i<strlen(arr);i++){
if( i%(strlen(arr)/seg) == 0 ){
vrc[i/(strlen(arr)/seg)]=arr[i];
continue;
}
if(vrc[i/(strlen(arr)/seg)]==arr[i]){
vrc[i/(strlen(arr)/seg)]='0';
}
else{
vrc[i/(strlen(arr)/seg)]='1';
}
}

for(i=0;i<strlen(arr);i++){
if( i<(strlen(arr)/seg) ){
lrc[i]=arr[i];
continue;
}
if(lrc[i%(strlen(arr)/seg)]==arr[i]){
lrc[i%(strlen(arr)/seg)]='0';
}
else{
lrc[i%(strlen(arr)/seg)]='1';
}
}

cout<<"\n\n2D parity is :\n\n";


for(i=0;i<strlen(arr);i++){
cout<<" "<<arr[i]<<" ";

if( ( (i) % (strlen(arr)/seg) ) == (strlen(arr)/seg)-1 ){


cout<<"| "<<vrc[i/(strlen(arr)/seg)]<<" "<<endl;
}
}

for(i=0;i<(strlen(arr)/seg);i++){
cout<<"-----";
}
cout<<endl;

for(i=0;i<(strlen(arr)/seg);i++){
cout<<" "<<lrc[i]<<" ";
}
cout<<endl;
return 0;
}

Output:
Experiment 8:

Aim: Implement Bellman Ford Algorithm using C/C++.

Theory : The Bellman-Ford algorithm [FORD62] can be stated as follows: Find the
shortest paths from a given source node subject to the constraint that the paths
contain at most one link, then find the shortest paths with a constraint of paths of at
most two links, and so on. Given a graph and a source vertex source in graph, find
shortest paths from source to all vertices in the given graph. The graph may
contain negative weight edges.

The Bellman-Ford algorithm calculates shortest paths in a bottom-up manner. It


first calculates the shortest distances which have at-most one edge in the path.
Then, it calculates the shortest paths with at-most 2 edges, and so on. After the i-th
iteration of the outer loop, the shortest paths with at most i edges are calculated.
There can be maximum |V| – 1 edge in any simple path, that is why the outer loop
runs |v| – 1 time. The idea is, assuming that there is no negative weight cycle if we
have calculated shortest paths with at most i edges, then an iteration over all edges
guarantees to give the shortest path with at-most (i+1) edges.
Program :

#include <bits/stdc++.h>

struct Edge {
intsrc, dest, weight;
};

struct Graph {

int V, E;

struct Edge* edge;


};

struct Graph* createGraph(int V, int E)


{
struct Graph* graph = new Graph;
graph->V = V;
graph->E = E;
graph->edge = new Edge[E];
return graph;
}

void printArr(intdist[], int n)


{
printf("Vertex Distance from Source\
n"); for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}

void BellmanFord(struct Graph* graph, intsrc)


{
int V = graph-
>V; int E =
graph->E;
intdist[V];

for (int i = 0; i < V; i++)


dist[i] = INT_MAX;
dist[src] = 0;
for (int i = 1; i <= V - 1; i++) {
for (int j = 0; j < E; j++) {
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX &&dist[u] + weight <dist[v])
dist[v] = dist[u] + weight;
}
}

for (int i = 0; i < E; i++) {


int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] != INT_MAX &&dist[u] + weight <dist[v]) {
printf("Graph contains negative weight cycle");
return; // If negative cycle is detected, simply return
}
}

printArr(dist, V);
return;
}

// Driver program to test above functions


int main()
{
/* Let us create the graph given in above example */
int V = 5; // Number of vertices in graph
int E = 8; // Number of edges in graph
struct Graph* graph = createGraph(V,
E);
// add edge 0-1 (or A-B in above
figure) graph->edge[0].src = 0;
graph->edge[0].dest = 1;
graph->edge[0].weight = -1;
// add edge 0-2 (or A-C in above
figure) graph->edge[1].src = 0;
graph->edge[1].dest = 2;
graph->edge[1].weight = 4;
// add edge 1-2 (or B-C in above figure)
graph->edge[2].src = 1;
graph->edge[2].dest = 2;
graph->edge[2].weight = 3;
// add edge 1-3 (or B-D in above figure)
graph->edge[3].src = 1;
graph->edge[3].dest = 3;
graph->edge[3].weight = 2;
// add edge 1-4 (or A-E in above
figure) graph->edge[4].src = 1;
graph->edge[4].dest = 4;
graph->edge[4].weight = 2;
// add edge 3-2 (or D-C in above figure)
graph->edge[5].src = 3;
graph->edge[5].dest = 2;
graph->edge[5].weight = 5;
// add edge 3-1 (or D-B in above figure)
graph->edge[6].src = 3;
graph->edge[6].dest = 1;
graph->edge[6].weight = 1;
// add edge 4-3 (or E-D in above figure)
graph->edge[7].src = 4;
graph->edge[7].dest = 3;
graph->edge[7].weight = -3;
BellmanFord(graph, 0);
return 0;

Output:
Experiment 7:

Aim: Implement checksum using C/C++.

Theory: In checksum error detection scheme, the data is divided into k segments
each of m bits. In the sender’s end the segments are added using 1’s complement
arithmetic to get the sum. The sum is complemented to get the checksum. The
checksum segment is sent along with the data segments. At the receiver’s end, all
received segments are added using 1’s complement arithmetic to get the sum. The
sum is complemented. If the result is zero, the received data is accepted; otherwise
discarded.

The checksum detects all errors involving an odd number of bits. It also detects
most errors involving even number of bits.

(a) Sender’s end for the calculation of the checksum, (b) Receiving end for
checking the checksum
Program:

#include<iostream>

#include<string.h>

using namespace std;

int main()

char a[20],b[20];

char sum[20],complement[20];

int i;

cout<<"Enter first binary string\n";

cin>>a;

cout<<"Enter second binary string\n";

cin>>b;

if(strlen(a)==strlen(b))

char carry='0';

int length=strlen(a);

for(i=length-1;i>=0;i--)

if(a[i]=='0' && b[i]=='0' && carry=='0')

sum[i]='0';
carry='0';

else if(a[i]=='0' && b[i]=='0' && carry=='1')

sum[i]='1';

carry='0';

else if(a[i]=='0' && b[i]=='1' && carry=='0')

sum[i]='1';

carry='0';

else if(a[i]=='0' && b[i]=='1' && carry=='1')

sum[i]='0';

carry='1';

else if(a[i]=='1' && b[i]=='0' && carry=='0')

sum[i]='1';

carry='0';

else if(a[i]=='1' && b[i]=='0' && carry=='1')


{

sum[i]='0';

carry='1';

else if(a[i]=='1' && b[i]=='1' && carry=='0')

sum[i]='0';

carry='1';

else if(a[i]=='1' && b[i]=='1' && carry=='1')

sum[i]='1';

carry='1';

else

break;

cout<<"\nSum="<<carry<<sum;

for(i=0;i<length;i++)

if(sum[i]=='0')

complement[i]='1';

else
complement[i]='0';

if(carry=='1')

carry='0';

else

carry='1';

cout<<"\nChecksum="<<carry<<complement;

else

cout<<"\nWrong input strings";

return 0;

Output:

You might also like