TIKARAM P.G.
GIRLS COLLEGE
SONIPAT
SESSION : {2024-2025}
PRACTICAL FILE
OF
COMPUTER NETWORKS
SUBMITTED TO :- MRS. POOJA MAM
SUBMITTED BY :- DIVYA
MSC. (CS )1ST YEAR
ROLL NO. :- 5005
UNIVERSITY ROLL NO.:-
INDEX
S.No. PROGRAM NAME SIGN.
1. Write a program to simulate bus topology.
2. Write a program to simulate star topology.
3. Write a program to simulate ring topology.
4. Write a program to simulate mesh topology.
5. Write a program to demonstrate the difference
between digital and analog signals using simple
sine waves and square waves.
6. Install and Configure wire and wireless NIC.
7. Connect the computer in Local Area Network.
8. Program to demonstrate simplex: half- duplex
communication using text- based examples.
9. Program to demonstrate simplex: full- duplex
10. Install and configure Network Devices: Routers.
11. Configure Host IP, Subnet Mask and Default.
12. Program to simulate a basic circuit switching
network where a connection is established
before communication.
13. Program to simulate packet switching with
packet fragmentation and reassembly.
14. Program to input and validate IPv4
15. Program to input and validate IPv6 addresses.
1.)Write a program to simulate
bus topology.
Steps for Simulating a Bus Topology in Cisco Packet
Tracer:
1. Create the Network
You will simulate a bus topology using the following
components:
• 1 Hub (acting as the central "bus")
• Several computers or devices connected to this hub
via coaxial cable or copper cables.
2. Place Devices in Packet Tracer
1. Add a Switch (simulating the "bus" or central
connection).
2. Add Computers or other devices (PCs, servers, etc.).
3. Connect all devices to the switch using Ethernet
cables.
3. Set up the Devices (Example with PCs):
Example IP configuration for three devices:
• PC1: 192.168.1.2 /24
• PC2: 192.168.1.3 /24
• PC3: 192.168.1.4 /24
Steps:
• Click on the PC and go to the Desktop tab.
• Click on IP Configuration.
• Set the IP Address and Subnet Mask.
4. Connect the Devices:
• Use the copper straight-through cable to connect
the PCs to the switch.
5. Verify Communication Between Devices:
After setting up the devices and IP addresses, you can
test communication between the devices using the ping
command.
• Open the Command Prompt on one of the PCs
(Desktop > Command Prompt).
• Type ping 192.168.1.3 (to ping PC2 from PC1) and
check if the ping is successful.
• Repeat the same for the other PCs.
Example Packet Tracer Configuration:
PC1 Configuration:
• IP Address: 192.168.1.2
• Subnet Mask: 255.255.255.0
PC2 Configuration:
• IP Address: 192.168.1.3
• Subnet Mask: 255.255.255.0
PC3 Configuration:
• IP Address: 192.168.1.4
• Subnet Mask: 255.255.255.0
Testing Connectivity:
1. From PC1, ping PC2:
C:\> ping 192.168.1.3
2. From PC2, ping PC1:
C:\> ping 192.168.1.2
2.)Write a program to simulate
star topology.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DEVICES 5
// Device structure to represent a node in the network
typedef struct
{
int deviceId;
char deviceName[50];
int isActive;
} Device;
// Hub structure that connects devices
typedef struct
{
Device devices[MAX_DEVICES];
int deviceCount;
} Hub;
// Function to initialize a new device
void initDevice(Device *device, int id, const char *name)
{
device->deviceId = id;
strcpy(device->deviceName, name); device->isActive = 1;
// Device is active by default
}
// Function to initialize the hub
void initHub(Hub *hub)
{ hub->deviceCount = 0;
}
// Function to add a device to the hub
int addDeviceToHub(Hub *hub, Device *device)
{
if (hub->deviceCount < MAX_DEVICES)
{ hub->devices[hub->deviceCount] = *device;
hub->deviceCount++;
return 1;
// Device added successfully
}
else
{
return 0;
// Hub is full, cannot add more devices }
}
// Function to send a message from the hub to a device
void sendMessage(Hub *hub, int deviceId, const char
*message)
{
int found = 0;
for (int i = 0; i < hub->deviceCount; i++) { if (hub-
>devices[i].deviceId == deviceId && hub-
>devices[i].isActive)
{
printf("Message sent to %s (Device ID: %d): %s\n", hub-
>devices[i].deviceName, hub->devices[i].deviceId,
message);
found = 1;
break; }
}
if (!found)
{
printf("Error: Device not found or inactive.\n");
}
}
// Function to simulate communication between devices
through the hub
void simulateCommunication(Hub *hub)
{
char message[100];
printf("Enter a message to send: ");
fgets(message, sizeof(message), stdin);
message[strcspn(message, "\n")] = 0;
// Remove newline character
for (int i = 0; i < hub->deviceCount; i++)
{
sendMessage(hub, hub->devices[i].deviceId, message);
}
}
int main()
{
Hub hub;
Device device1, device2, device3, device4, device5;
// Initialize the hub
initHub(&hub);
// Initialize devices and add them to the hub
initDevice(&device1, 1, "Device 1");
initDevice(&device2, 2, "Device 2");
initDevice(&device3, 3, "Device 3");
initDevice(&device4, 4, "Device 4");
initDevice(&device5, 5, "Device 5");
addDeviceToHub(&hub, &device1);
addDeviceToHub(&hub, &device2);
addDeviceToHub(&hub, &device3);
addDeviceToHub(&hub, &device4);
addDeviceToHub(&hub, &device5);
// Simulate communication
simulateCommunication(&hub);
return 0;
}
OUTPUT:-
Enter a message to send: Hello, Devices!
Message sent to Device 1 (Device ID: 1): Hello, Devices!
Message sent to Device 2 (Device ID: 2): Hello, Devices!
Message sent to Device 3 (Device ID: 3): Hello, Devices!
Message sent to Device 4 (Device ID: 4): Hello, Devices!
Message sent to Device 5 (Device ID: 5): Hello, Devices!
3.) Write a program to simulate
ring topology.
class Node:
def __init__(self, name):
self.name = name # Name of the node
self.next = None # Reference to the next node in the ring
self.prev = None # Reference to the previous node in the
ring
def send_data(self, data):
"""Send data to the next node in the ring.""" printf("Node
{self.name} sends data: {data}")
if self.next:
self.next.receive_data(data)
def receive_data(self, data):
"""Receive data and send it to the next node."""
printf("Node {self.name} received data: {data}")
self.send_data(data) # Pass the data to the next node
class RingTopology:
def __init__(self, node_names):
"""Initialize a ring topology with a list of node names."""
# Create nodes and link them in a circular fashion nodes
= [Node(name) for name in node_names] for i in
range(len(nodes)):
nodes[i].next = nodes[(i + 1) % len(nodes)] # next node
nodes[i].prev = nodes[(i - 1) % len(nodes)] # prev node
self.start_node = nodes[0] # Start from the first node
def start_transmission(self, data):
"""Start data transmission from the first node."""
printf("Starting data transmission with data: {data}")
self.start_node.send_data(data)
# Example usage
if __name__ == "__main__":
# Create a ring topology with nodes A, B, C, D
node_names = ["A", "B", "C", "D"]
ring = RingTopology(node_names)
# Start transmitting data around the ring
ring.start_transmission("Hello, Ring!")
OUTPUT:-
Starting data transmission with data: Hello, Ring! Node A
sends data: Hello, Ring!
Node A received data: Hello, Ring!
Node B sends data: Hello, Ring!
Node B received data: Hello, Ring!
Node C sends data: Hello, Ring!
Node C received data: Hello, Ring!
Node D sends data: Hello, Ring!
Node D received data: Hello, Ring!
Node A sends data: Hello, Ring!......
4.) Write a program to simulate
mesh topology.
class MeshNetwork:
def __init__(self, num_devices):
# Initialize the mesh network with 'num_devices'
self.num_devices = num_devices
# Create an adjacency matrix to represent the
network's connections
self.adj_matrix = [[0 for _ in range(num_devices)] for _
in range(num_devices)]
self.create_mesh_topology()
def create_mesh_topology(self):
# In a full mesh, each device is connected to every
other device
for i in range(self.num_devices):
for j in range(self.num_devices):
if i != j:
self.adj_matrix[i][j] = 1 # 1 indicates a direct
connection
def display_network(self):
print("Mesh Topology (Adjacency Matrix):")
for row in self.adj_matrix:
print(row)
def is_connected(self, device1, device2):
# Check if device1 is directly connected to device2
if 0 <= device1 < self.num_devices and 0 <= device2 <
self.num_devices:
return self.adj_matrix[device1][device2] == 1
else:
return False
def add_device(self):
# Add a new device to the mesh network
self.num_devices += 1
# Expand the adjacency matrix to include the new
device
for row in self.adj_matrix:
row.append(1) # Connect new device to existing
devices
self.adj_matrix.append([1] * self.num_devices) # New
device is connected to all existing devices
def remove_device(self, device):
# Remove a device from the network and adjust the
matrix
if 0 <= device < self.num_devices:
self.num_devices -= 1
# Remove the row and column corresponding to
the device
del self.adj_matrix[device]
for row in self.adj_matrix:
del row[device]
def network_summary(self):
# Print summary information about the network
print(f"Number of devices: {self.num_devices}")
print("Direct connections between devices:")
for i in range(self.num_devices):
for j in range(self.num_devices):
if i != j and self.adj_matrix[i][j] == 1:
print(f"Device {i} <-> Device {j}")
# Example usage:
if __name__ == "__main__":
# Create a mesh network with 4 devices
network = MeshNetwork(4)
# Display the network's adjacency matrix
network.display_network()
# Check if two devices are connected
print("\nIs Device 1 connected to Device 3?",
network.is_connected(1, 3))
# Add a new device to the network
network.add_device()
network.display_network()
# Remove a device from the network
network.remove_device(2)
network.display_network()
# Display a summary of the network
network.network_summary()
OUTPUT:-
Mesh Topology (Adjacency Matrix):
[0, 1, 1, 1]
[1, 0, 1, 1]
[1, 1, 0, 1]
[1, 1, 1, 0]
Is Device 1 connected to Device 3? True
Mesh Topology (Adjacency Matrix):
[0, 1, 1, 1, 1]
[1, 0, 1, 1, 1]
[1, 1, 0, 1, 1]
[1, 1, 1, 0, 1]
[1, 1, 1, 1, 0]
Mesh Topology (Adjacency Matrix):
[0, 1, 1, 1]
[1, 0, 1, 1]
[1, 1, 0, 1]
[1, 1, 1, 0]
Number of devices: 4
Direct connections between devices:
Device 0 <-> Device 1
Device 0 <-> Device 2
Device 0 <-> Device 3
Device 1 <-> Device 0
Device 1 <-> Device 2
Device 1 <-> Device 3
Device 2 <-> Device 0
Device 2 <-> Device 1
Device 2 <-> Device 3
Device 3 <-> Device 0
Device 3 <-> Device 1
Device 3 <-> Device 2
5.) Write a program to demonstrate
the difference between digital and
analog signals using simple sine
waves and square waves.
import numpy as np
import matplotlib.pyplot as plt
# Set the parameters for the signals
sampling_rate = 1000 # Samples per second (higher value
for smoothness)
duration = 1 # Duration in seconds
frequency = 5 # Frequency of the signals (in Hz)
# Generate time vector (from 0 to 'duration' with
'sampling_rate' samples per second)
t = np.linspace(0, duration, sampling_rate)
# Analog signal: Sine wave (continuous signal)
analog_signal = np.sin(2 * np.pi * frequency * t)
# Digital signal: Square wave (discrete signal)
digital_signal = np.sign(np.sin(2 * np.pi * frequency * t))
# Plot the signals
plt.figure(figsize=(10, 6))
# Plot Analog Signal (Sine wave)
plt.subplot(2, 1, 1)
plt.plot(t, analog_signal, label="Analog Signal (Sine Wave)",
color='b')
plt.title("Analog Signal - Sine Wave")
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.grid(True)
plt.legend()
# Plot Digital Signal (Square wave)
plt.subplot(2, 1, 2)
plt.plot(t, digital_signal, label="Digital Signal (Square
Wave)", color='r')
plt.title("Digital Signal - Square Wave")
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.grid(True)
plt.legend()
# Show the plots
plt.tight_layout()
plt.show()
OUTPUT:-
• The sine wave demonstrates a smooth, continuous
change in amplitude, characteristic of analog signals.
• The square wave demonstrates abrupt transitions
between discrete values (high and low),
characteristic of digital signals.
6.) Install and Configure wire
and wireless NIC.
• Install the Wired NIC (Ethernet)
1. Check for available NICs: Open a terminal and use
the following command to list all available network
interfaces:
ip a
or
ifconfig -a
2. Check if the wired NIC is recognized: The wired
NIC will likely be named something like eth0, enp3s0,
or similar. If it's recognized, you can proceed to
configure it.
3. Enable and configure DHCP (Dynamic IP): Most
modern systems use Network Manager to configure
the network. You can enable the wired interface and
get an IP address using DHCP (assuming DHCP is
enabled on the router).
sudo nmcli device connect eth0
Replace eth0 with the actual interface name if
different.
4. Static IP Configuration (Optional): To configure a
static IP, edit the network settings. You can use nm-
connection-editor or manually edit the
/etc/netplan/*.yaml file for more advanced setups (for
Ubuntu 20.04+).
Example static IP configuration:
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: false
addresses:
- 192.168.1.100/24
gateway4: 192.168.1.1
nameservers:
addresses:
- 8.8.8.8
- 8.8.4.4
Apply the changes:
sudo netplan apply
• Install the Wireless NIC (Wi-Fi)
1. Check if the Wi-Fi NIC is recognized: To check if
your wireless card is recognized, use:
ip a
2. Install necessary drivers: Some wireless cards
require additional drivers. Use the following
commands to ensure your Wi-Fi drivers are
installed.
On Ubuntu, for most popular Wi-Fi cards (Intel,
Broadcom, etc.), you can install the necessary
drivers:
sudo apt update
sudo apt install linux-firmware
sudo apt install firmware-b43-installer # for
Broadcom cards
3. Enable and connect to Wi-Fi: Use nmcli to scan for
available networks:
nmcli device wifi list
Then, connect to your Wi-Fi network:
nmcli device wifi connect "SSID" password
"yourpassword"
4. Network Manager GUI (Optional): If you're using a
GUI, you can configure your Wi-Fi network using the
Network Manager applet in the system tray.
c. Verify the Network Configuration
After configuring both interfaces, you can verify that they
are connected and have an IP address using:
ip a
7.) Connect the computer in Local
Area Network.
1. Gather Required Equipment
• Computer with a network adapter.
• Router or Switch (for wired connections).
• Ethernet Cable (for wired connections).
• Wi-Fi
2. Wired LAN Connection (Ethernet Cable)
• Step 1: Plug one end of the Ethernet cable into the
computer’s network port (Ethernet port).
• Step 2: Plug the other end of the Ethernet cable into
an available port on the router or switch.
• Step 3: Ensure the router is powered on and
properly connected to the internet (if needed).
• Step 4: The computer should automatically detect
the wired connection. Check for a network icon in
the system tray (Windows) or menu bar (Mac) to
confirm the connection.
3. Wireless LAN Connection (Wi-Fi)
• Step 1: Ensure your computer’s Wi-Fi adapter is
turned on.
• Step 2: On your computer, go to the network
settings:
o Windows: Click on the Wi-Fi icon in the taskbar,
then select your Wi-Fi network.
• Step 3: Choose the network you wish to join and
enter the Wi-Fi password (if required).
• Step 4: Once connected, you should see the Wi-Fi
icon indicating a successful connection.
4. Test the Connection
• Open a web browser or command prompt to test the
network.
o Windows: Open Command Prompt and type
ping 192.168.1.1 (assuming the router’s default IP
is 192.168.1.1).
o Mac/Linux: Open Terminal and type ping
192.168.1.1.
5. Troubleshooting
• If the connection is not working:
o Check the Ethernet cable or Wi-Fi signal.
o Ensure the router and modem are functioning.
o Restart the computer and router.
o Verify network settings, such as IP address and
subnet mask.
8.) Program to demonstrate
simplex: half- duplex
communication using text- based
examples
class HalfDuplexCommunication:
def __init__(self):
self.sender_data = ""
self.receiver_data = ""
def send_data(self, data):
self.sender_data = data
print(f"Sender: Sending data - {data}")
def receive_data(self):
if self.sender_data:
self.receiver_data = self.sender_data
print(f"Receiver: Receiving data -
{self.receiver_data}")
self.sender_data = "" # Clear data after it's
received
else:
print("Receiver: No data to receive.")
def communication_turn(self, turn):
if turn == 'sender':
message = input("Enter message to send: ")
self.send_data(message)
elif turn == 'receiver':
self.receive_data()
else:
print("Invalid turn!")
# Simulating half-duplex communication
half_duplex = HalfDuplexCommunication()
# Alternating turns for sending and receiving
while True:
turn = input("Who's turn is it? (sender/receiver/quit):
").strip().lower()
if turn == 'quit':
print("Ending communication.")
break
elif turn in ['sender', 'receiver']:
half_duplex.communication_turn(turn)
else:
print("Invalid input! Please enter 'sender', 'receiver',
or 'quit'.")
OUTPUT:-
Who's turn is it? (sender/receiver/quit): sender
Enter message to send: Hello Receiver, I am sending the
first message!
Sender: Sending data - Hello Receiver, I am sending the
first message!
Who's turn is it? (sender/receiver/quit): receiver
Receiver: Receiving data - Hello Receiver, I am sending
the first message!
Who's turn is it? (sender/receiver/quit): sender
Enter message to send: Now it's your turn to send
something.
Sender: Sending data - Now it's your turn to send
something.
Who's turn is it? (sender/receiver/quit): receiver
Receiver: Receiving data - Now it's your turn to send
something.
Who's turn is it? (sender/receiver/quit): quit
Ending communication.
9.) Program to demonstrate
simplex: full- duplex
import time
import threading
# Simplex communication simulation
class SimplexChannel:
def __init__(self):
self.message = None
self.lock = threading.Lock()
def send(self, message):
with self.lock:
self.message = message
print(f"Sent (Simplex): {message}")
def receive(self):
with self.lock:
if self.message:
print(f"Received (Simplex): {self.message}")
self.message = None
else:
print("No message to receive.")
# Full-duplex communication simulation
class FullDuplexChannel:
def __init__(self):
self.incoming = None
self.outgoing = None
self.lock = threading.Lock()
def send(self, message):
with self.lock:
self.outgoing = message
print(f"Sent (Full-duplex): {message}")
def receive(self):
with self.lock:
if self.incoming:
print(f"Received (Full-duplex): {self.incoming}")
self.incoming = None
else:
print("No incoming message.")
def set_incoming_message(self, message):
with self.lock:
self.incoming = message
# Functions for simulation
def simplex_communication():
simplex_channel = SimplexChannel()
def sender():
for i in range(1, 6):
time.sleep(1)
simplex_channel.send(f"Message {i} from Sender")
def receiver():
for _ in range(5):
time.sleep(2)
simplex_channel.receive()
sender_thread = threading.Thread(target=sender)
receiver_thread = threading.Thread(target=receiver)
sender_thread.start()
receiver_thread.start()
sender_thread.join()
receiver_thread.join()
def full_duplex_communication():
full_duplex_channel = FullDuplexChannel()
def sender():
for i in range(1, 6):
time.sleep(1)
full_duplex_channel.send(f"Message {i} from
Sender")
full_duplex_channel.set_incoming_message(f"Reply
to {i} from Receiver")
def receiver():
for _ in range(5):
time.sleep(1.5)
full_duplex_channel.receive()
sender_thread = threading.Thread(target=sender)
receiver_thread = threading.Thread(target=receiver)
sender_thread.start()
receiver_thread.start()
sender_thread.join()
receiver_thread.join()
# Main function to demonstrate both simplex and full-
duplex
def main():
print("Starting Simplex Communication Simulation:")
simplex_communication()
print("\nStarting Full-Duplex Communication
Simulation:")
full_duplex_communication()
if __name__ == "__main__":
main()
OUTPUT:-
Starting Simplex Communication Simulation:
Sent (Simplex): Message 1 from Sender
Received (Simplex): Message 1 from Sender
Sent (Simplex): Message 2 from Sender
Received (Simplex): Message 2 from Sender
Sent (Simplex): Message 3 from Sender
Received (Simplex): Message 3 from Sender
Sent (Simplex): Message 4 from Sender
Received (Simplex): Message 4 from Sender
Sent (Simplex): Message 5 from Sender
Received (Simplex): Message 5 from Sender
Starting Full-Duplex Communication Simulation:
Sent (Full-duplex): Message 1 from Sender
Received (Full-duplex): Reply to 1 from Receiver
Sent (Full-duplex): Message 2 from Sender
Received (Full-duplex): Reply to 2 from Receiver
Sent (Full-duplex): Message 3 from Sender
Received (Full-duplex): Reply to 3 from Receiver
Sent (Full-duplex): Message 4 from Sender
Received (Full-duplex): Reply to 4 from Receiver
Sent (Full-duplex): Message 5 from Sender
Received (Full-duplex): Reply to 5 from Receiver
10.) Install and configure Network
Devices: Routers
• Installing the Router:
Physical Installation:
1. Unbox and check the router:
o Ensure you have all necessary components: the
router itself, power adapter, cables (Ethernet),
and documentation.
2. Place the router:
o Position the router in a central location within
your network or close to your modem (for
internet connectivity).
o Ensure good ventilation to prevent overheating.
3. Connect power:
o Plug the router into a power source using the
supplied power adapter.
4. Connect to the modem:
o For Internet Access:
§ Connect the router’s WAN or Internet port
to the modem using an Ethernet cable.
§ The modem should provide the router with
an internet connection via this port.
o For LAN connections:
§ Connect the router’s LAN ports to your
devices (e.g., computers, printers, or
switches) via Ethernet cables.
Installing and configuring a router involves several key
steps. Routers connect networks together and route data
between them, typically within a local area network
(LAN) or between a LAN and the internet. Below are
general steps for installing and configuring routers,
whether you're working with a home router or a more
complex enterprise router
• Router Configuration : (Cisco Router)
If you're using an enterprise-grade router like a Cisco
router, the setup might involve configuring through the
command-line interface (CLI).
Here’s a basic example for a Cisco router:
1. Access the Router’s CLI:
o Connect via console cable or SSH.
o Log in to the router.
2. Basic Setup:
Router> enable
Router# configure terminal
Router(config)# hostname MyRouter
Router(config)# interface gigabitEthernet 0/0
Router(config-if)# ip address 192.168.1.1 255.255.255.0
Router(config-if)# no shutdown
Router(config-if)# exit
Router(config)# ip route 0.0.0.0 0.0.0.0 [next-hop-IP]
# Set default route
Router(config)# line vty 0 4
Router(config-line)# password [password]
Router(config-line)# login
Router(config-line)# exit
Router(config)# enable secret [enable-password]
Router(config)# end
Router# write memory
3. Verify Configuration:
o show ip interface brief to check the status of
interfaces.
o ping [IP address] to test connectivity.
4. Save Configuration:
o write memory or copy running-config startup-
config to save the configuration.
11.) Configure Host IP, Subnet
Mask and Default
Windows (via GUI)
1. Open Network Connections:
o Press Windows + R to open the Run dialog.
o Type ncpa.cpl and press Enter. This opens the
"Network Connections" window.
2. Select Network Adapter:
o Right-click on the network adapter you want to
configure (e.g., Ethernet or Wi-Fi) and select
Properties.
3. Configure TCP/IPv4:
o In the Properties window, scroll to find
Internet Protocol Version 4 (TCP/IPv4) and
click it, then click the Properties button.
4. Set IP, Subnet Mask, and Default Gateway:
o IP Address: Enter the desired IP address (e.g.,
192.168.1.100).
o Subnet Mask: Enter the subnet mask (e.g.,
255.255.255.0).
o Default Gateway: Enter the default gateway IP
address (e.g., 192.168.1.1).
5. DNS Servers (optional but recommended):
o For DNS, you can set it to Obtain DNS server
address automatically, or manually enter DNS
servers (e.g., Google's DNS: 8.8.8.8 and 8.8.4.4).
6. Apply Settings:
o Click OK to apply the settings.
12.) Program to simulate a basic
circuit switching network where a
connection is established before
communication.
class CircuitSwitchingNetwork:
def __init__(self, nodes):
self.nodes = nodes # List of node names
self.adj_list = {node: [] for node in nodes} #
Adjacency list
self.reserved_paths = {} # Dictionary to store
reserved paths between nodes
def add_link(self, node1, node2):
""" Add a bidirectional link between two nodes """
if node2 not in self.adj_list[node1]:
self.adj_list[node1].append(node2)
if node1 not in self.adj_list[node2]:
self.adj_list[node2].append(node1)
def find_path(self, start, end, path=None):
""" Find an available path from start to end using
DFS (Depth First Search) """
if path is None:
path = []
path.append(start)
if start == end:
return path # Found the path
for neighbor in self.adj_list[start]:
if neighbor not in path and not self.is_reserved(start,
neighbor):
# Recursively search for a path
new_path = self.find_path(neighbor, end,
path.copy())
if new_path:
return new_path
return None # No path found
def is_reserved(self, node1, node2):
""" Check if a link between node1 and node2 is
reserved """
return (node1, node2) in self.reserved_paths or
(node2, node1) in self.reserved_paths
def reserve_path(self, path):
""" Reserve the links in the path for communication
"""
for i in range(len(path) - 1):
self.reserved_paths[(path[i], path[i + 1])] = True
self.reserved_paths[(path[i + 1], path[i])] = True #
Bidirectional reservation
def free_path(self, path):
""" Free the reserved links in the path after
communication ends """
for i in range(len(path) - 1):
del self.reserved_paths[(path[i], path[i + 1])]
del self.reserved_paths[(path[i + 1], path[i])] #
Free both directions
def establish_connection(self, start, end):
""" Establish a circuit-switched connection """
print(f"Requesting connection from {start} to
{end}...")
path = self.find_path(start, end)
if path:
print(f"Path found: {' -> '.join(path)}")
self.reserve_path(path)
return path
else:
print(f"No available path between {start} and
{end}")
return None
def transfer_data(self, start, end):
""" Simulate data transfer after the path is
established """
path = self.establish_connection(start, end)
if path:
print(f"Transferring data from {start} to {end}...")
print(f"Data transfer successful! Using path: {' ->
'.join(path)}")
self.free_path(path)
print(f"Connection between {start} and {end} is
now terminated.\n")
else:
print("Data transfer failed due to no available
path.\n")
# Example usage
if __name__ == "__main__":
# Initialize the network with nodes
network = CircuitSwitchingNetwork(["A", "B", "C", "D",
"E"])
# Add some links between nodes
network.add_link("A", "B")
network.add_link("A", "C")
network.add_link("B", "D")
network.add_link("C", "D")
network.add_link("D", "E")
# Try to establish some connections and transfer data
network.transfer_data("A", "E")
network.transfer_data("B", "E")
network.transfer_data("A", "D")
OUTPUT:-
Requesting connection from A to E...
Path found: A -> C -> D -> E
Reserving path: A -> C -> D -> E
Transferring data from A to E...
Data transfer successful! Using path: A -> C -> D -> E
Connection between A and E is now terminated.
Requesting connection from B to E...
Path found: B -> D -> E
Reserving path: B -> D -> E
Transferring data from B to E...
Data transfer successful! Using path: B -> D -> E
Connection between B and E is now terminated.
Requesting connection from A to D...
Path found: A -> C -> D
Reserving path: A -> C -> D
Transferring data from A to D...
Data transfer successful! Using path: A -> C -> D
Connection between A and D is now terminated.
13.) Program to simulate packet
switching with packet
fragmentation and reassembly
import random
import time
from collections import defaultdict
# Constants
MTU = 8 # Maximum Transmission Unit (max size of
each fragment, in bytes)
HEADER_SIZE = 2 # 2 bytes for the header (identifier +
fragment offset)
PAYLOAD_SIZE = MTU - HEADER_SIZE # Size of the data
in each fragment
# Class to represent a Packet
class Packet:
def __init__(self, data):
self.data = data # Full data of the original packet
self.size = len(data) # Size of the packet
self.fragments = [] # List of fragments (each will be a
PacketFragment)
def fragment(self):
"""Fragment the packet into smaller pieces if it
exceeds MTU."""
total_size = self.size
offset = 0
fragment_id = random.randint(1000, 9999) # Unique
identifier for this packet
while offset < total_size:
fragment_data =
self.data[offset:offset+PAYLOAD_SIZE]
self.fragments.append(PacketFragment(fragment_id,
offset, fragment_data))
offset += PAYLOAD_SIZE
def get_fragments(self):
return self.fragments
# Class to represent a Packet Fragment
class PacketFragment:
def __init__(self, packet_id, offset, data):
self.packet_id = packet_id # Unique packet identifier
self.offset = offset # The position of this fragment in
the original packet
self.data = data # The data in this fragment
def __repr__(self):
return f"Fragment(packet_id={self.packet_id},
offset={self.offset}, data='{self.data}')"
# Function to simulate sending packets over a network
def send_packet(packet, network):
"""Simulates sending a packet and fragments over the
network."""
packet.fragment() # Fragment the original packet if
necessary
for fragment in packet.get_fragments():
network.receive_fragment(fragment)
# Network class to handle fragmentation, transmission,
and reassembly
class Network:
def __init__(self):
self.received_fragments = defaultdict(list) # Store
fragments by packet_id
self.reassembled_packets = {} # Store reassembled
packets by packet_id
def receive_fragment(self, fragment):
"""Simulate receiving a fragment and storing it."""
print(f"Received {fragment}")
self.received_fragments[fragment.packet_id].append(fragm
ent)
# Attempt to reassemble the packet if all fragments
are received
self.reassemble(fragment.packet_id)
def reassemble(self, packet_id):
"""Attempt to reassemble a packet from its
fragments."""
fragments = self.received_fragments[packet_id]
if len(fragments) == len(set(f.offset for f in
fragments)): # If all fragments are received
print(f"Reassembling packet with ID
{packet_id}...")
# Sort fragments by their offset and concatenate
the data
fragments = sorted(fragments, key=lambda f:
f.offset)
reassembled_data = ''.join(f.data for f in
fragments)
# Verify reassembled packet size matches original
if len(reassembled_data) == len(fragments[0].data)
* len(fragments):
self.reassembled_packets[packet_id] =
reassembled_data
print(f"Packet {packet_id} reassembled:
{reassembled_data}")
else:
print(f"Error: Unable to reassemble packet
{packet_id}")
else:
print(f"Waiting for more fragments of packet
{packet_id}...")
# Simulate a network with packet switching,
fragmentation, and reassembly
def main():
# Create a sample data packet
data = "Hello, this is a large packet that will be
fragmented!"
print(f"Original Packet: {data}\n")
packet = Packet(data)
network = Network()
# Simulate sending the packet
send_packet(packet, network)
# Simulate network delays and reordering of
fragments
random.shuffle(network.received_fragments[packet.get_fr
agments()[0].packet_id])
# Simulate a brief wait for all fragments to be received
time.sleep(1)
# Check the reassembled packets
print("\nReassembled Packets in Network:")
for packet_id, reassembled_data in
network.reassembled_packets.items():
print(f"Packet {packet_id}: {reassembled_data}")
if __name__ == "__main__":
main()
OUTPUT:-
Original Packet: Hello, this is a large packet that will be
fragmented!
Received Fragment(packet_id=1021, offset=0, data='Hello,
')
Received Fragment(packet_id=1021, offset=8, data='this is
')
Received Fragment(packet_id=1021, offset=16, data='a
large ')
Received Fragment(packet_id=1021, offset=24,
data='packet ')
Received Fragment(packet_id=1021, offset=32, data='that
wi')
Received Fragment(packet_id=1021, offset=40, data='ll be
f')
Received Fragment(packet_id=1021, offset=48,
data='ragmented!')
Reassembling packet with ID 1021...
Packet 1021 reassembled: Hello, this is a large packet that
will be fragmented!
Reassembled Packets in Network:
Packet 1021: Hello, this is a large packet that will be
fragmented!
14.) Program to input and validate
IPv4
import re
def is_valid_ipv4(ip):
# Regular expression to match a valid IPv4 address
pattern = r'^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-
5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-
9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
# Match the input string to the pattern
return bool(re.match(pattern, ip))
# Input the IP address
ip_address = input("Enter an IPv4 address: ")
# Validate the input IP address
if is_valid_ipv4(ip_address):
print(f"{ip_address} is a valid IPv4 address.")
else:
print(f"{ip_address} is not a valid IPv4 address.")
Example usage:-
Enter an IPv4 address: 192.168.1.1
192.168.1.1 is a valid IPv4 address.
Enter an IPv4 address: 256.168.1.1
256.168.1.1 is not a valid IPv4 address.
15.) Program to input and validate
IPv6 addresses.
import re
def validate_ipv6(ipv6):
# Regular expression to match valid IPv6 address
# It allows both the full form and the compressed form
with "::"
pattern = re.compile(r'^([0-9a-fA-F]{1,4}:){7}([0-9a-fA-
F]{1,4})$|^([0-9a-fA-F]{1,4}:){1,7}:$|^::([0-9a-fA-
F]{1,4}:){1,7}$|^([0-9a-fA-F]{1,4}:){0,7}([0-9a-fA-
F]{1,4}){0,1}::([0-9a-fA-F]{1,4}){0,7}$')
# Check if the input matches the pattern
if pattern.match(ipv6):
return True
else:
return False
def main():
ipv6_address = input("Enter an IPv6 address: ")
if validate_ipv6(ipv6_address):
print(f"The IPv6 address '{ipv6_address}' is valid.")
else:
print(f"The IPv6 address '{ipv6_address}' is invalid.")
if __name__ == "__main__":
main()
SAMPLE RUN:-
Enter an IPv6 address:
2001:0db8:85a3:0000:0000:8a2e:0370:7334
The IPv6 address
'2001:0db8:85a3:0000:0000:8a2e:0370:7334' is valid.
Enter an IPv6 address: 2001:db8::ff00:42:8329
The IPv6 address '2001:db8::ff00:42:8329' is valid.
Enter an IPv6 address: 2001:db8:123:abc
The IPv6 address '2001:db8:123:abc' is invalid.