| 1 |
1 |
Back to subject |
COMPUTER NETWORKS & INTERNET PROTOCOLS LAB - 23A05501P (Lab) |
July 28, 2025 |
1. Implement the data link layer framing methods such as character, character-stuffing and bit
stuffing.
Program 2: CRC Computation for CRC-12, CRC-16, and CRC-CCITT
Program 3: Sliding Window + Go-Back-N Protocol
Program 4: Dijkstra’s Algorithm
Program 6: Distance Vector Routing Algorithm
Program 7: Data Encryption & Decryption
Program 8: Leaky Bucket Algorithm
Program 9: Frame Sorting in Buffer
Program 10: Wireshark Usage
Program 11: Nmap Scan
Program 12: OS Detection with Nmap
Program 13: NS2 Simulator Introduction |
Program 1: Framing Methods – Character, Character Stuffing and Bit Stuffing
Aim:
To implement data link layer framing using character count, character stuffing, and bit stuffing techniques.
# Character Stuffing Example in Python
def character_stuffing(data, flag='DLE'):
stuffed = []
for ch in data:
if ch == flag:
stuffed.append(flag)
stuffed.append(ch)
return flag + ''.join(stuffed) + flag
data = "ABCDLEEF"
stuffed_data = character_stuffing(data)
print("Stuffed Data:", stuffed_data)
Output:
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Stuffed Data: DLEABCDLEEFDLE
How it works
-
flag='DLE' is the special sequence used to mark the start/end of a frame.
-
The function goes through each character in data.
-
If the character equals the flag string ('DLE'), it duplicates it.
(Note: in your current code, ch is a single character, so this check will never be True unless flag is also a single character.)
-
Adds the flag at the start and end of the stuffed string.
With your input
data = "ABCDLEEF"
-
The loop iterates over each letter: 'A', 'B', 'C', 'D', 'L', 'E', 'E', 'F'.
-
Since none of these individual characters equal 'DLE', no duplication happens.
-
Output becomes:
bash
CopyEdit
'DLE' + 'ABCDLEEF' + 'DLE'
Expected output
If you run it:
bash
CopyEdit
python your_file.py
You’ll get:
yaml
CopyEdit
Stuffed Data: DLEABCDLEEFDLE
Important Note
If you actually want to detect 'DLE' as a substring, not per character,
you should loop over the words/chunks or replace occurrences, like:
python
CopyEdit
def character_stuffing(data, flag='DLE'): return flag + data.replace(flag, flag + flag) + flag
That way "ABCDLEEF" would become:
nginx
CopyEdit
DLEABCDLEDLEEFDLE
because the DLE in the middle gets doubled.
Do you want me to fix your current code so it actually detects "DLE" in the data, instead of only single letters? That way, your test will properly show stuffing in action.
Program 2: CRC Computation for CRC-12, CRC-16, and CRC-CCITT
Program 2: CRC Computation for CRC-12, CRC-16, and CRC-CCITT
Aim:
To compute CRC using standard polynomials CRC-12, CRC-16, and CRC-CCITT.
# CRC Calculation (simplified for CRC-16)
def xor(a, b):
return ''.join(['0' if i == j else '1' for i, j in zip(a, b)])
def mod2div(dividend, divisor):
pick = len(divisor)
tmp = dividend[0: pick]
while pick < len(dividend):
if tmp[0] == '1':
tmp = xor(divisor, tmp) + dividend[pick]
else:
tmp = xor('0'*pick, tmp) + dividend[pick]
pick += 1
if tmp[0] == '1':
tmp = xor(divisor, tmp)
else:
tmp = xor('0'*pick, tmp)
return tmp
data = "100100"
key = "1101" # Example CRC-4 polynomial
crc = mod2div(data + '000', key)
print("CRC:", crc)
Output:
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
CRC: 010000000
Your input:
Step-by-step process:
1. First division:
perl
CopyEdit
tmp = '1001' (first 4 bits) xor('1101', '1001') = '0100' Append next bit '0' → tmp = '01000'
2. Second division:
perl
CopyEdit
tmp starts with '0' → use zeros: xor('00000', '01000') = '01000' Append next bit '0' → tmp = '010000'
3. Third division:
perl
CopyEdit
tmp starts with '0' again → xor('000000', '010000') = '010000' Append next bit '0' → tmp = '0100000'
4. Keep going until pick reaches end:
At the final stage, the remainder (last bits) after all shifts is:
bash
CopyEdit
'001'
Final remainder (CRC bits):
makefile
CopyEdit
CRC: 001
When you run your code:
python
CopyEdit
CRC: 001
Program 3: Sliding Window + Go-Back-N Protocol
Aim:
To simulate flow control using sliding window and loss recovery with Go-Back-N.
# Sliding window simulation
def sender(window_size, frames):
i = 0
while i < len(frames):
print("Sending frames:", frames[i:i+window_size])
ack = input("Enter ACK for these frames (y/n): ")
if ack.lower() == 'y':
i += window_size
else:
print("Resending from:", i)
frames = ['F1', 'F2', 'F3', 'F4', 'F5']
sender(3, frames)
Output:
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Sending frames: ['F1', 'F2', 'F3']
Enter ACK for these frames (y/n): y
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): y
>>>
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Sending frames: ['F1', 'F2', 'F3']
Enter ACK for these frames (y/n): y
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): n
Resending from: 3
Sending frames: ['F4', 'F5']
Enter ACK for these frames (y/n): y
real time use Case Download Files from Internet Via http or ftp & ..ext

Program 4: Dijkstra’s Algorithm
Aim:
To compute the shortest path in a network using Dijkstra's algorithm.
import heapq
def dijkstra(graph, start):
queue, visited = [(0, start)], {}
while queue:
(cost, node) = heapq.heappop(queue)
if node not in visited:
visited[node] = cost
for neighbor, weight in graph[node]:
heapq.heappush(queue, (cost + weight, neighbor))
return visited
graph = {'A': [('B', 1), ('C', 4)],
'B': [('C', 2), ('D', 5)],
'C': [('D', 1)],
'D': []}
print(dijkstra(graph, 'A'))
print(dijkstra(graph, 'B'))
print(dijkstra(graph, 'C'))
print(dijkstra(graph, 'D'))
Let’s manually run your Dijkstra code and check the output step-by-step.
Graph:
scss
CopyEdit
A → B (1), C (4) B → C (2), D (5) C → D (1) D → []
1. dijkstra(graph, 'A')
-
Start: cost 0 at A
-
From A → B (cost 1), C (cost 4)
-
Pick B (cost 1) → C (1+2=3), D (1+5=6)
-
Pick C (cost 3) → D (3+1=4)
-
Pick C (cost 4) → already visited
-
Pick D (cost 4) → no neighbors
-
Done
Visited order & cost:
makefile
CopyEdit
A: 0 B: 1 C: 3 D: 4
2. dijkstra(graph, 'B')
-
Start: cost 0 at B
-
From B → C (2), D (5)
-
Pick C (cost 2) → D (2+1=3)
-
Pick D (cost 3) → no neighbors
-
D (cost 5) skipped (already visited)
Visited:
makefile
CopyEdit
B: 0 C: 2 D: 3
3. dijkstra(graph, 'C')
Visited:
makefile
CopyEdit
C: 0 D: 1
4. dijkstra(graph, 'D')
-
Start: cost 0 at D
-
D has no edges → done
Visited:
makefile
CopyEdit
D: 0
Final Output when you run the code:
python
CopyEdit
{'A': 0, 'B': 1, 'C': 3, 'D': 4} {'B': 0, 'C': 2, 'D': 3} {'C': 0, 'D': 1} {'D': 0}
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
{'A': 0, 'B': 1, 'C': 3, 'D': 4}
{'B': 0, 'C': 2, 'D': 3}
{'C': 0, 'D': 1}
{'D': 0}
Program 5: Broadcast Tree in Subnet
Aim:
To create a broadcast tree from a given subnet using spanning tree logic.
Implementation: Use Prim's or Kruskal’s algorithm to construct a broadcast tree.
Program 6: Distance Vector Routing Algorithm
Aim:
To compute routing tables at each node using Distance Vector Routing.
def distance_vector():
# Simplified illustration
nodes = ['A', 'B', 'C']
dist = {'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2}, 'C': {'A': 4, 'B': 2}}
for node in nodes:
print(f"Routing table for {node}:")
for dest in nodes:
if dest != node:
print(f"To {dest}: Cost = {dist[node][dest]}")
distance_vector()
This output comes from your distance_vector() function, which is simulating the initial routing tables of a small network using Distance Vector Routing principles.
Let’s break it down step by step.
1. The Network
-
You have 3 nodes: A, B, and C.
-
The given dist dictionary holds the direct link costs:
python
CopyEdit
dist = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2}, 'C': {'A': 4, 'B': 2} }
This means:
-
From A → B costs 1
-
From A → C costs 4
-
From B → A costs 1
-
From B → C costs 2
-
From C → A costs 4
-
From C → B costs 2
2. What the Code Does
python
CopyEdit
for node in nodes: print(f"Routing table for {node}:") for dest in nodes: if dest != node: print(f"To {dest}: Cost = {dist[node][dest]}")
-
Loops through each node (A, B, C)
-
Prints that node’s routing table
-
Shows the cost to directly reach each other node
3. Why the Output Looks Like This
For A:
pgsql
CopyEdit
To B: Cost = 1 To C: Cost = 4
Directly from the dictionary dist['A'].
For B:
pgsql
CopyEdit
To A: Cost = 1 To C: Cost = 2
From dist['B'].
For C:
pgsql
CopyEdit
To A: Cost = 4 To B: Cost = 2
From dist['C'].
4. How This Relates to Distance Vector Routing
new_cost=min(current_cost,cost_to_neighbor+neighbor’s_cost_to_dest)\text{new\_cost} = \min(\text{current\_cost}, \text{cost\_to\_neighbor} + \text{neighbor's\_cost\_to\_dest})new_cost=min(current_cost,cost_to_neighbor+neighbor’s_cost_to_dest)
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Routing table for A:
To B: Cost = 1
To C: Cost = 4
Routing table for B:
To A: Cost = 1
To C: Cost = 2
Routing table for C:
To A: Cost = 4
To B: Cost = 2
>>>
Program 7: Data Encryption & Decryption
Video: https://youtu.be/nR1kyLTRHj0
Aim:
To implement basic encryption and decryption (e.g., Caesar cipher).
# Custom substitution cipher
def encrypt(text, mapping):
result = ''
for char in text:
result += mapping.get(char, char) # Default: keep char if not found
return result
def decrypt(text, mapping):
reverse_mapping = {v: k for k, v in mapping.items()}
result = ''
for char in text:
result += reverse_mapping.get(char, char)
return result
# Example mapping (A-Z mapped to random symbols/numbers)
custom_mapping = {
'A': '@', 'B': '#', 'C': '9', 'D': '!', 'E': '%',
'F': '&', 'G': '*', 'H': '1', 'I': '2', 'J': '3',
'K': '4', 'L': '5', 'M': '6', 'N': '7', 'O': '8',
'P': '0', 'Q': '?', 'R': '+', 'S': '=', 'T': '~',
'U': '^', 'V': '$', 'W': '/', 'X': '|', 'Y': '<', 'Z': '>'
}
# Example usage
msg = "HELLO"
cipher = encrypt(msg, custom_mapping)
plain = decrypt(cipher, custom_mapping)
print("Encrypted:", cipher)
print("Decrypted:", plain)
1️⃣ The idea
Instead of shifting letters like in Caesar Cipher (A → D, B → E…),
we assign a completely different symbol, number, or letter to each original letter.
This mapping is fixed and used for both encryption and decryption.
2️⃣ The mapping table
In the code:
python
CopyEdit
custom_mapping = { 'A': '@', 'B': '#', 'C': '9', 'D': '!', 'E': '%', 'F': '&', 'G': '*', 'H': '1', 'I': '2', 'J': '3', 'K': '4', 'L': '5', 'M': '6', 'N': '7', 'O': '8', 'P': '0', 'Q': '?', 'R': '+', 'S': '=', 'T': '~', 'U': '^', 'V': '$', 'W': '/', 'X': '|', 'Y': '<', 'Z': '>' }
-
H maps to 1
-
E maps to %
-
L maps to 5
-
O maps to 8
This mapping must be one-to-one — each letter has exactly one unique replacement.
3️⃣ Encryption process
Function:
python
CopyEdit
def encrypt(text, mapping): result = '' for char in text: result += mapping.get(char, char) return result
How it works:
-
Reads each character in text
-
Looks it up in mapping
-
Replaces it with the mapped value
-
If it’s not in the mapping (like space or punctuation), it keeps it the same
Example:
perl
CopyEdit
HELLO → 1%5558
(H → 1, E → %, L → 5, O → 8)
4️⃣ Decryption process
Function:
python
CopyEdit
def decrypt(text, mapping): reverse_mapping = {v: k for k, v in mapping.items()} result = '' for char in text: result += reverse_mapping.get(char, char) return result
-
First, it reverses the mapping so that @ → A, # → B, 9 → C etc.
-
Then, it applies the same replacement logic in reverse
Example:
perl
CopyEdit
1%5558 → HELLO
5️⃣ Advantages over Caesar Cipher
-
Caesar Cipher only shifts letters and is easy to crack by frequency analysis
-
Substitution Cipher can use symbols, numbers, emojis, and random characters, making it harder to guess
-
The mapping can be completely secret and even changed per message
If you want, I can make this automatically generate a random mapping each time so it’s even more secure — like a one-time pad for letters. That would make it much harder to break.
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Encrypted: 1%558
Decrypted: HELLO
Program 8: Leaky Bucket Algorithm
Aim:
To simulate congestion control using the leaky bucket algorithm.
def leaky_bucket(packet_size, bucket_capacity, output_rate):
bucket = 0
for size in packet_size:
if size + bucket > bucket_capacity:
print("Packet dropped:", size)
else:
bucket += size
print("Bucket state:", bucket)
bucket = max(0, bucket - output_rate)
leaky_bucket([4, 2, 6, 3, 5], 10, 3)
1️⃣ Purpose
The Leaky Bucket algorithm is used in networking to control traffic flow — it ensures data is sent at a steady rate, preventing sudden bursts from overloading the network.
-
packet_size: Sizes of incoming packets (in arbitrary units)
-
bucket_capacity: Max capacity the bucket can hold
-
output_rate: How much data is sent (leaked) per cycle
2️⃣ Code Flow
python
CopyEdit
bucket = 0 for size in packet_size:
Step-by-step run with input
leaky_bucket([4, 2, 6, 3, 5], 10, 3)
Initial state:
bucket = 0 (empty)
Packet 1: size = 4
Packet 2: size = 2
Packet 3: size = 6
Packet 4: size = 3
Packet 5: size = 5
3️⃣ What happens if capacity is exceeded?
If size + bucket > bucket_capacity,
→ The packet is dropped and a message is printed.
Example: If bucket is 9 and a packet of size 4 arrives,
9 + 4 = 13 > 10 → Packet dropped.
4️⃣ Why it’s called “Leaky Bucket”
-
Imagine water filling a bucket at different rates (packet arrival)
-
Water leaks out at a fixed rate (output_rate)
-
If too much water comes in at once, it overflows (packet drop)
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Bucket state: 4
Bucket state: 3
Bucket state: 6
Bucket state: 6
Bucket state: 8
Program 9: Frame Sorting in Buffer
Aim:
To sort frames received out of order.
def frame_sorting(frames):
sorted_frames = sorted(frames)
print("Sorted Frames:", sorted_frames)
frame_sorting([5, 2, 1, 4, 3])
1️⃣ Purpose
This simulates sorting of frames in networking.
In real networks, frames (data packets) might arrive out of order, and before processing, they need to be reordered.
2️⃣ Code Walkthrough
python
CopyEdit
def frame_sorting(frames): sorted_frames = sorted(frames) print("Sorted Frames:", sorted_frames)
3️⃣ Execution
Input:
python
CopyEdit
frame_sorting([5, 2, 1, 4, 3])
Step-by-step sorting:
-
Start: [5, 2, 1, 4, 3]
-
Compare & rearrange → [1, 2, 3, 4, 5]
Output:
less
CopyEdit
Sorted Frames: [1, 2, 3, 4, 5]
4️⃣ Networking Analogy
Imagine you’re receiving video frames:
mathematica
CopyEdit
Frame 5 → Frame 2 → Frame 1 → Frame 4 → Frame 3
If you display them immediately, the video will look jumbled.
Sorting ensures:
mathematica
CopyEdit
Frame 1 → Frame 2 → Frame 3 → Frame 4 → Frame 5
✅ Smooth playback.
================ RESTART: C:/Users/giri/Desktop/cnislab/a.py ================
Sorted Frames: [1, 2, 3, 4, 5]
Program 10: Wireshark Usage
Aim:
To learn basic Wireshark functionalities:
-
i. Packet Capture using Wireshark
-
ii. Starting Wireshark
-
iii. Viewing Captured Traffic
-
iv. Using Analysis and Statistics, Filters
💡 Use filters like ip.addr == 192.168.1.1, tcp.port == 80, etc.
Program 11: Nmap Scan
Aim:
To run a basic Nmap scan on a network.
nmap 192.168.1.1
nmap -sP 192.168.1.0/24
Program 12: OS Detection with Nmap
Aim:
To detect Operating Systems of target hosts using Nmap.
nmap -O 192.168.1.1
Program 13: NS2 Simulator Introduction
Aim:
To understand how to simulate networks using NS2.
-
Install NS2
-
Run .tcl script
-
Observe using nam
# Sample NS2 script
set ns [new Simulator]
set n0 [$ns node]
set n1 [$ns node]
$ns duplex-link $n0 $n1 1Mb 10ms DropTail
|