Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
6 views73 pages

DCN Notes

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 73

1 / 73

EXERCISE 1: COMMAND LINE TOOLS


AIM:

To allow users to perform various network-related tasks and diagnostics directly


from the command line interface (CLI) of an operating system and to provide a way
to interact with network devices, troubleshoot network issues, and gather
information about network configurations.

PING COMMAND:
• The ping command is a network diagnostic tool used to test the reachability
and latency (response time) of a remote host or IP address. It is available on
most operating systems, including Windows, macOS, and Linux.
• When you execute the ping command followed by a target host or IP address,
the command sends out small packets of data to the specified destination.
The target host then responds to these packets, allowing you to measure the
time it takes for the packets to reach the destination and return.
1. Basic Ping:
ping <host or IP>
This command sends ICMP echo requests to the specified host or IP address and
displays the round-trip time (RTT) for each reply. It continues to send echo requests
until interrupted.
2 / 73

2. Specify Number of Echo Requests:


ping -c <count> <host or IP>
The -c option allows you to specify the number of ICMP echo requests to send. It
sends the specified number of requests and stops afterward, displaying the
statistics.

3. Set Ping Interval:


ping -i <interval> <host or IP>
The -i option sets the interval in seconds between each ICMP echo request. It
controls the rate at which the requests are sent.

4. DNS Reverse Lookup:


ping -a <IP>
The -a option is used to perform a reverse DNS lookup of the specified IP address. It
attempts to determine the corresponding hostname of the given IP.
3 / 73

5. Specify Packet Size:


ping -s <size> <host or IP>
The -s option allows you to specify the size in bytes of the ICMP echo request packet.
This can be used to test the maximum transmission unit (MTU) of the network.

6. To Set Time Limit:


ping -w <size> <hostname>
To stop receiving a ping output after a specific amount of time, add -
w and an interval in seconds to your command.

TRACEROUTE:
• Traceroute is a network diagnostic tool used to track the path that packets
take from your computer to a target host or IP address on a network. It
provides information about each hop (router) along the path, showing the IP
addresses and response times for each hop.
• To use the traceroute command in Linux, follow these steps:
• Open a terminal: Launch a terminal application on your Linux system. You can
typically find it in the applications menu or by using the search function.
4 / 73

• Run the traceroute command: In the terminal, type the following command:
traceroute <host or IP>
• Replace <host or IP> with the target host or IP address you want to trace the
route to. For example
traceroute www.example.com
• View the output: Press Enter to execute the command. The traceroute
command will start sending packets to the target and display the information
about each hop in the route. The output will include the hop number, IP
address, and round-trip time (RTT) for each hop.
• Analyze the output: Review the output to identify the route taken by the
packets and examine the RTT values. Higher RTT values may indicate network
congestion or latency at that particular hop.
• Stop the traceroute: The traceroute command will continue sending packets
until it reaches the maximum hop limit (usually 30 hops) or until you interrupt
it manually by pressing Ctrl+C in the terminal.
• Note: The traceroute command in Linux may require administrative (root)
privileges to function properly. If you encounter any issues or receive
"Permission denied" errors, try executing the command with sudo:
sudo traceroute <host or IP>
Using sudo will prompt you to enter your password before executing the command.
5 / 73

NETSTAT:

The netstat command allows you to monitor and analyze various aspects of network
activity on your system. It provides details such as active network connections,
listening ports, routing tables, and network interface statistics. By using netstat, you
can gather valuable information about network performance, troubleshooting
network issues, and identifying active connections.
Here are some common uses of the netstat command:
1. Displaying Active Network Connections:
netstat -a
This command shows all active network connections, including TCP, UDP, and Unix
domain sockets.

2. Displaying Listening Ports:


netstat -l
This command lists all the ports on which the system is listening for incoming
connections.
6 / 73

3. Displaying Network Statistics


netstat -s
This command provides comprehensive statistics for various network protocols,
such as TCP, UDP, ICMP, and IP.

4. Displaying Routing Table


netstat -r
This command shows the system's routing table, including destination networks,
gateways, and interface information.
7 / 73

To use the netstat command, follow these steps:


• Open a terminal or command prompt: Launch the terminal application or
command prompt on your operating system.
• Execute the netstat command: In the terminal or command prompt, type
the netstat command followed by the desired options and parameters.

For example:
netstat -a
This command will display all active network connections.

DIG:
• The dig command, short for "Domain Information Groper," is a command-
line network administration tool used to perform DNS (Domain Name
System) queries.
• It is commonly available on Unix-like operating systems, including Linux and
macOS.
• The dig command allows you to retrieve various types of DNS information
from DNS servers.
• It provides a flexible and powerful way to query DNS records, troubleshoot
DNS-related issues, and gather DNS-related information
8 / 73

OTHER NETWORK COMMAND LINE TOOLS:

IFCONFIG:
ifconfig (interface configuration) is a command-line tool used to configure and
display the network interface parameters on a Unix-like system. It allows you to
view and modify the IP address, network masks, network interfaces, and other
network-related configurations.

IWCONFIG:
iwconfig is a command-line tool used to configure and display wireless network
interface parameters on Linux systems. It provides information about wireless
interfaces, such as SSID (network name), mode, channel, encryption, and signal
strength.

ROUTE:
Route is a command-line tool used to view and manipulate the IP routing table on
a Unix-like system. It allows you to examine and modify the routing information
used by the operating system to determine how network packets are forwarded
between different networks or subnets
9 / 73

MTR:
MTR (My traceroute) is a command-line network diagnostic tool that combines
the functionality of ping and traceroute. It continuously sends ICMP echo requests
to the target host while providing detailed information about each hop in the
route, including round-trip times, packet loss, and network latency

Result:
In conclusion, network command line tools are essential utilities for network
administrators, developers, and users who need to perform network-related tasks,
diagnostics, and troubleshooting from the command line interface. These network
command tools are tested and verified.
10 / 73

EXERCISE 2: PING AND TRACEROUTE


AIM:
To simulate PING and TRACEROUTE commands using Twisted Python.

PROCEDURE:

• The Ping application should send ICMP Echo Request packetsto a specified
target host or IP address and measure the round-trip time (RTT) for each
packet.
• The application should display the RTT for each packet received, as well as
the overall statistics, including packet loss percentage and average RTT.

• The Traceroute application should send UDP packets with increasing TTL
values to a specified target host or IP address and print out the
intermediate hops along the path.
• The application should display the IP address or hostname of each
intermediate hop and the round-trip time (RTT) for each hop.

CODE
PING

import subprocess
from twisted.internet import reactor, defer

class PingProtocol:
def __init__(self):
self.deferred = defer.Deferred()

def ping(self, host):


process = subprocess.Popen(['ping', '-c', '4', host],
stdout=subprocess.PIPE)
output, error = process.communicate()
if error:
self.deferred.errback(error)
else:
self.deferred.callback(output)

def print_result(result):
print(result.decode())

def print_error(failure):
print(failure)
11 / 73

protocol = PingProtocol()
protocol.ping('google.com')
protocol.deferred.addCallbacks(print_result, print_error)
reactor.run()

TRACEROUTE

import subprocess
from twisted.internet import reactor, defer

class TracerouteCmd:
def __init__(self):
self.deferred = defer.Deferred()

def traceroute(self, host):


process = subprocess.Popen(['traceroute', '-m', '10', host],
stdout=subprocess.PIPE)
output, error = process.communicate()
if error:
self.deferred.errback(error)
else:
self.deferred.callback(output)

def print_result(result):
print(result.decode())

def print_error(failure):
print(failure)

protocol = TracerouteCmd()
protocol.traceroute('google.com')
protocol.deferred.addCallbacks(print_result, print_error)
reactor.run()
12 / 73

OUTPUT

RESULT
Hence, the ping and traceroute commands are implemented using twisted python
and verified the output successfully.
13 / 73

EXERCISE 3: NETWORK TOPOLOGIES


AIM:
To simulate the four basic network topologies (Star, Mesh, Ring, and Bus) using
Twisted Python.

PROCEDURE:
1. Start with an empty network topology.
2. Determine the number of nodes or devices to be included in the network.
3. Decide on the type of topology to construct (e.g., star, ring, bus, mesh, tree).
4. Create the nodes or devices for the network and assign unique identifiers to
each node.
5. If using a pre-defined topology (e.g., star), connect each node to a central
node or hub.
6. If using a dynamic topology (e.g., mesh), determine the connection scheme
based on your requirements.
7. For each node, determine its connections or neighbors based on the chosen
topology.
8. Establish the connections between nodes by creating links or channels.
9. Assign appropriate parameters to the links, such as bandwidth, latency, and
reliability.
10.Store or represent the network topology in a suitable data structure, such as
a graph or adjacency list.
11.Provide methods or functions to access and manipulate the network
topology as needed.
12.Optionally, visualize or display the network topology using appropriate tools
or libraries.
13.Test the constructed network topology by performing simulations or
running network protocols on it.
14.Iterate and refine the topology construction process as necessary based on
the desired network characteristics and requirements.
14 / 73

CODE
BUS TOPOLOGY:

from twisted.internet import reactor, protocol

class DropLink(protocol.Protocol):
def __init__(self, factory):
self.factory = factory
self.name = None

def connectionMade(self):
self.factory.clients.append(self)
print("New client connected to bus backbone.")

def connectionLost(self, reason):


self.factory.clients.remove(self)
print("Client disconnected.")

def dataReceived(self, data):


message = data.decode().strip()
if not self.name:
self.name = message
print(f"{self.name} connected to bus.")
else:
if message.startswith("@"):
recipient, private_message = message[1:].split(":", 1)
self.sendPrivateMessage(recipient, private_message)
else:
print(f"{self.name}: {message}")
self.broadcastMessage(f"{self.name}: {message}")

def sendPrivateMessage(self, recipient, message):


for client in self.factory.clients:
if client.name == recipient:
client.transport.write(f"(Private) {self.name}:
{message}\n".encode())
break
else:
self.transport.write(f"Error: User {recipient} not
found.\n".encode())

def broadcastMessage(self, message):


for client in self.factory.clients:
if client != self:
client.transport.write(f"{message}\n".encode())

class BusBackbone(protocol.Factory):
15 / 73

def __init__(self):
self.clients = []

def buildProtocol(self, addr):


return DropLink(self)

if __name__ == "__main__":
reactor.listenTCP(8000, BusBackbone())
print("Bus server started.")
print("Enter your name as first message to register. To send a message to a
particular username use '@username: message'.")
reactor.run()

MESH TOPOLOGY:

from twisted.internet import reactor, protocol

class MeshProtocol(protocol.Protocol):
def __init__(self, factory):
self.factory = factory
self.name = None

def connectionMade(self):
self.factory.clients.append(self)
print("New client connected.")

def connectionLost(self, reason):


self.factory.clients.remove(self)
print("Client disconnected.")

def dataReceived(self, data):


message = data.decode().strip()
if not self.name:
self.name = message
print(f"{self.name} joined the chat.")
else:
if message.startswith("@"):
recipient, private_message = message[1:].split(":", 1)
self.sendPrivateMessage(recipient, private_message)
else:
print(f"{self.name}: {message}")
self.broadcastMessage(f"{self.name}: {message}")

def sendPrivateMessage(self, recipient, message):


for client in self.factory.clients:
if client.name == recipient:
16 / 73

client.transport.write(f"(Private) {self.name}:
{message}\n".encode())
break
else:
self.transport.write(f"Error: User {recipient} not
found.\n".encode())

def broadcastMessage(self, message):


for client in self.factory.clients:
if client != self:
client.transport.write(f"{message}\n".encode())

class MeshFactory(protocol.Factory):
def __init__(self):
self.clients = []

def buildProtocol(self, addr):


return MeshProtocol(self)

if __name__ == "__main__":
reactor.listenTCP(8000, MeshFactory())
print("Bus server started.")
print("Enter your name as first message to register. To send a message to a
particular username use '@username: message'.")
reactor.run()

STAR TOPOLOGY:

from twisted.internet import protocol, reactor

class StarProtocol(protocol.Protocol):
def __init__(self, factory):
self.factory = factory # factory that stores all the clients connected
to the server
self.name = None # name of the client that will connect to the server

def connectionMade(self):
'''establishing a connection to the server'''
print('New client connected: ', self.transport.getPeer())
self.factory.clients.append(self)

def connectionLost(self, reason):


print("Client disconnected")
self.factory.remove(self)

def dataReceived(self, data):


message = data.decode().strip()
17 / 73

if not self.name:
self.name = message
print(self.name, ' has connected to the server.') # if the client
has not connected
else:
if message.startswith('@'):
# already existing client sends a message
'''one client will send message to another client '''
recipient, private_message = message[1:].split(":", 1)
self.sendthroughServer(recipient, private_message)
else:
'''if destination is not specified, the message is simply sent to
the server.'''
self.transport.write(message)

def sendthroughServer(self, recipient, message):


self.transport.write(message) # the message first goes to the server
self.transport.write('message sending.....')
self.sendPrivateMessage(recipient, message) # destination through the
server

def sendPrivateMessage(self, recipient, message):


for client in self.factory.clients:
if client.name == recipient:
client.transport.write(f"(Private) {self.name}:
{message}\n".encode())
break
else:
self.transport.write(f"Error: User {recipient} not
found.\n".encode())

class StarFactory(protocol.Factory):
def __init__(self):
self.clients = []

def buildProtocol(self, addr):


# the message is then sent to the
return StarProtocol()

if __name__ == "__main__":
reactor.listenTCP(8080, StarFactory())
print("Server started. Listening on port 8080...")
print("Enter client name to register. Enter @ before the starting of a
message to send message to another client.")
reactor.run()
18 / 73

RING TOPLOGY:

from twisted.internet import protocol, reactor

class RingProtocol(protocol.Protocol):
def __init__(self, factory):
self.factory = factory
self.name = None

def connectionMade(self):
print('New client connected: ', self.transport.getPeer())
self.factory.clients.append(self)

def connectionLost(self, reason):


print("Client disconnected")
index = self.factory.clients.index(self)
self.factory.clients[index] = None

def dataReceived(self, data):


message = data.decode().strip()
if not self.name:
self.name = message
print(self.name, ' has connected to the server.')
self.factory.names.append(self.name) # if the client has not
connected to the server before
else:
if message.startswith('@'):
recipient, private_message = message[1:].split(":", 1)
receiver_index = self.factory.names.index(recipient)
sender_index = self.factory.names.index(self.name)
while sender_index != receiver_index:
sender_index += 1
if sender_index == len(self.factory.names):
sender_index = 0
if self.factory.clients[sender_index] is None:
self.transport.write('link failure. message cannot be
sent'.encode())
break
self.sendPrivateMessage(self.factory.names[sender_index],
private_message)
else:
self.transport.write(message.encode())

def sendPrivateMessage(self, recipient, message):


for client in self.factory.clients:
if client is not None:
if client.name == recipient:
19 / 73

client.transport.write(f"(Private) {self.name}:
{message}\n".encode())
break
else:
self.transport.write(f"Error: User {recipient} not
found.\n".encode())

class RingFactory(protocol.Factory):
def __init__(self):
self.clients = []
self.names = []

def buildProtocol(self, addr):


return RingProtocol(self)

if __name__ == "__main__":
reactor.listenTCP(8080, RingFactory())
print("Server started. Listening on port 8080...")
print("Enter client name to register. Enter @ before the starting of a
message to send message to another client.")
reactor.run()

OUTPUT:
20 / 73

RESULT:
Hence, the four basic network topologies such as Star, Mesh, Ring and Bus have
been implemented using Twisted Python and verified the output successfully.
21 / 73

EXERCISE 4: NETWORK PACKET ANALYSING

AIM:

To perform network capture using Wireshark by applying various filters

PROCEDURE

• Wireshark is free open-source packet analyser. It is mainly used for network


troubleshooting and analysis. Using Wireshark software, network capture
has to done and analysis has to be performed.
• Open ubuntu software and in the explore tab search for Wireshark.
• To run: enter the command sudo wireshark in ubuntu terminal
• Below the menu bar, spot the display filter bar and enter the name of the
protocol. This is how a display filter is applied .

RUNNING AND OUTPUTS


a) TCP packets

It is designed to send packets across the internet and ensure the successful
delivery of data and messages over network.
22 / 73

b) ARP packets

The Address Resolution Protocol is a communication protocol used for discovering


the link layer address, such as a MAC address, associated with a given internet
layer address.

c) DNS

Domain Name System (DNS) turns domain names into IP addresses, which allow
browsers to get to websites and other internet resources. Every device on the
internet has an IP address, which other devices can use to locate the device.
23 / 73

d) UDP

UDP is a short form for User Datagram protocol. It is one of the simplest transport
layer protocol. It is a connectionless and unreliable transport protocol.

e) HTTP

Hypertext Transfer Protocol,It uses encryption for secure communication over a


computer network, and is widely used on the Internet. In HTTPS, the
communication protocol is encrypted using Transport Layer Security or, formerly,
Secure Sockets Layer.

f) FTP

FTP (File Transfer Protocol) is a network protocol for transmitting files between
computers over Transmission Control Protocol/Internet Protocol (TCP/IP)
connections.
24 / 73

g) SMTP

The Simple Mail Transfer Protocol is an Internet standard communication protocol


for electronic mail transmission. Mail servers and other message transfer agents
use SMTP to send and receive mail messages

Result:
Thus, the required network packets has been captured and analysed using
Wireshark.
25 / 73

EXERCISE 5: NETWORK SIMULATION USING PACKET


TRACING
AIM:
To implement a simple network and different cases of the same using the CISCO
packet tracer application.

PROCEDURE:
1. Create an account on CISCO website.
2. Click on the installation link after logging in:
https://skillsforall.com/resources/lab- downloads?courseLang=en-US.
3. Connect devices as per the topology.
4. Basic configuration of the devices.
5. Assign IP address to the PC’s.
6. Test and verify the network connectivity (ping command)

RUNNING AND OUTPUTS


Mesh Topology (CASE 1: All cables intact):

[ On sending packets from source address: PC3 to other PC’s]


26 / 73

Initial:

Final:
27 / 73

Using ping command to verify connectivity:

Result:
Hence, the given topology was implemented successfully using CISCO packet
tracer.
28 / 73

EXERCISE 6: SOCKET PROGRAMMING


AIM:
To study the client-server model using socket programming to enable
communication between a client program and a server program over a network.

SOCKET PROGRAMMING:
• A socket is a communications connection point (endpoint) that you can
name and address in a network.
• Socket programming shows how to use socket APIs to establish
communication links between remote and local processes. One socket
(node) listens on a particular port at an IP, while the other socket reaches
out to the other to form a connection. The server forms the listener socket
while the client reaches out to the server.
• In socket programming, there are typically two roles: the client and the
server. Client: The client initiates a connection to a server. It can send
requests or messages to the server and receive responses.
• Server: The server listens for incoming connections from clients. It accepts
connections, processes client requests, and sends back responses.

FLOW DIAGRAM FOR SERVER AND CLIENT MODEL OF SOCKET


29 / 73

FUNCTIONS USED IN SERVER/CLIENT MODEL:


1. Create a socket:
Both the client and server need to create their respective sockets. A socket
is created using the socket() function, specifying the address family (such as
IPv4 or IPv6) and the socket type (such as TCP or UDP).
2. Bind (for server):
In the server program, the socket needs to be bound to a specific address
and port on the machine. This is done using the bind() function, which
associates a socket with an address.
3. Listen (for server):
The server socket needs to listen for incoming connections. The listen()
function is used to make the server socket ready to accept client
connections.
4. Connect (for client):
The client program needs to establish a connection to the server. The
connect() function is used to connect to the server's address and port.
5. Accept (for server):
When a client attempts to connect to the server, the server program uses
the accept() function to accept the connection and create a new socket for
communication with that client.
6. Send and receive data:
Once the connection is established, both the client and server can use the
send() and receive() functions to send and receive data between them. The
data can be in the form of bytes or strings.
7. Close the connection:
After the communication is complete, both the client and server should
close their sockets using the close() function.
To implement client-server model using twisted python, here are some of the key
functions and classes:
Server Side:
• reactor.listenTCP(port_number, factory): Starts a TCP server listening on the
specified port_number. It takes a Factory instance, which is responsible for
creating protocol instances for each client connection.
• twisted.protocols.Protocol: A base class that you can subclass to create your own
protocol for handling server-side logic. It provides methods like connectionMade(),
30 / 73

dataReceived(data), and connectionLost(reason) to handle different events in the


communication process.
• twisted.internet.protocol.Factory: A base class for creating protocol instances.
You can subclass it to define your own factory, which is responsible for creating
instances of your protocol class.
• reactor.run(): Starts the Twisted event loop, allowing your server to run and
handle incoming connections and data.
Client Side:
• reactor.connectTCP(server_ip, port_number, protocol_instance): Connects
to a server with the specified server_ip and port_number using the given
protocol_instance. The protocol instance should be an instance of your
custom protocol class, which extends twisted.protocols.Protocol.
• twisted.protocols.Protocol: Similar to the server side, this base class is used
to create your own protocol for handling client-side logic. You can
implement methods like connectionMade(), dataReceived(data), and
connectionLost(reason) to handle the corresponding events.
• reactor.run(): Starts the Twisted event loop, allowing your client to run and
interact with the server.

RESULT
Thus, the study of socket programming and client-server model have been done.
31 / 73

EXERCISE 7: TCP SOCKETS


AIM:
To implement TCP Echo Server and Echo Client, Chat Server and File Transfer
Applications using Twisted Python.

PROCEDURE:
ECHO CLIENT/SERVER
1. Based on the IP Address and Port Number the connection is established
between the Server and Client.
2. Port Number should be same in Server and Client.
3. Local Host should be specified in Client.
4. Client will have its data echoed back to server.
CHAT SERVER/CLIENT
1. For every client joining the server should be displayed and notified in the
chatroom with their names, for the clients who are already available.
2. All the messages sent by each client is listed out with their name.
Every message sent by each client is displayed to all the others present in
the chat room.
3. ‘/quit’ when entered can make the client lose connection with the chat
server.
FILE TRANSFER
1. initialize the server with a port number and directory path.
2. Handle the connection events (connection made, lost, and data received).
3. Implement the FTP commands (e.g., LIST, RETR, STOR) to handle client
requests.
4. Provide methods to manage file transfers and directory operations.
5. Run the server using reactor.listenTCP with the specified port number.
32 / 73

CODES
ECHO
echoserver.py
from twisted.internet import protocol,reactor
class echo(protocol.Protocol):
def dataReceived(self, data):
print("Message from Client -", data.decode())
print("Client Connected!")
ack_msg = f"{data.decode()}"
ack = "ACK[" + ack_msg + "]"
print("Acknoledgement Sent!")
self.transport.write(ack.encode())

class echofactory(protocol.Factory):
def buildProtocol(self, addr):
return echo()

reactor.listenTCP(8000,echofactory())
reactor.run()

echoclient.py
from twisted.internet import reactor, protocol
class EchoClient(protocol.Protocol):
def connectionMade(self):
msg = input("Enter the message to Server - ")
self.transport.write(msg.encode())
def dataReceived(self, data):
print ("Acknoledgement from Server -", data.decode())
self.transport.loseConnection()
class EchoFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return EchoClient()
def clientConnectionFailed(self, connector, reason):
print ("Connection failed.")
reactor.stop()
def clientConnectionLost(self, connector, reason):
print ("Connection lost.")
reactor.stop()
reactor.connectTCP("localhost", 8000, EchoFactory())
reactor.run()
33 / 73

CHAT
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineOnlyReceiver

class ChatProtocol(LineOnlyReceiver):
def __init__(self, factory):
self.factory = factory
self.name = None
self.state = "GETNAME"
self.client = None
def connectionMade(self):
self.sendLine("What's your name?".encode())
def connectionLost(self, reason):
if self.name in self.factory.users:
del self.factory.users[self.name]
self.broadcastMessage(f"{self.name} has left the chat room.")
def lineReceived(self, line):
if self.state == "GETNAME":
self.handle_GETNAME(line.decode())
else:
self.handle_CHAT(line.decode())
def handle_GETNAME(self, name):
if name in self.factory.users:
self.sendLine("Name already taken, please choose another
name.".encode())
return
self.sendLine(f"Welcome, {name}!".encode())
self.broadcastMessage(f"{name} has joined the chat room.")
self.name = name
self.factory.users[name] = self
self.state = "CHAT"
def handle_CHAT(self, message):
if message.lower() == "/quit":
self.transport.loseConnection()
else:
message = f"<{self.name}> {message}"
self.broadcastMessage(message)
def broadcastMessage(self, message):
for name, protocol in self.factory.users.items():
if protocol != self:
protocol.sendLine(message.encode())
def connectionMade(self):
self.sendLine("Connected to the chat server. Type '/quit' to
exit.".encode())
self.factory.clients.append(self)
def connectionLost(self, reason):
self.factory.clients.remove(self)
34 / 73

class ChatFactory(protocol.Factory):
def __init__(self):
self.users = {}
self.clients = []
def buildProtocol(self, addr):
return ChatProtocol(self)
def broadcastMessage(self, message):
for client in self.clients:
client.sendLine(message.encode())

if __name__ == "__main__":
reactor.listenTCP(9000, ChatFactory())
print("Chat server started. Listening on port 9000...")
reactor.run()

FILE TRANSFER
ftpserver.py
from twisted.internet import reactor, protocol
import os
import time
class FileTransferProtocol(protocol.Protocol):
def connectionMade(self):
print("Client connected.")
def dataReceived(self, data):
if data == b"SEND":
self.transport.write(b"READY")
self.transferFile = True
self.startTime = time.time() # Start measuring time
elif self.transferFile:
with open("received_file.txt", "wb") as f:
f.write(data)
self.transport.write(b"RECEIVED")
self.transferFile = False
endTime = time.time() # Stop measuring time
rtt = endTime - self.startTime
print("Round trip time:", rtt)
else:
self.transport.write(b"ERROR")

class FileTransferFactory(protocol.Factory):
def buildProtocol(self, addr):
return FileTransferProtocol()

if __name__ == "__main__":
reactor.listenTCP(7000, FileTransferFactory())
print("Server started.")
reactor.run()
35 / 73

ftpclient.py
from twisted.internet import reactor, protocol
import os
import time

class FileTransferClientProtocol(protocol.Protocol):
def connectionMade(self):
self.startTime = time.time() # Start measuring time
try:
f = open("myfile.txt", "rb")
self.fileData = f.read()
f.close()
if len(self.fileData) == 0:
print("File is empty.")
self.transport.loseConnection()
else:
self.transport.write(b"SEND")
except FileNotFoundError:
print("File not found.")
self.transport.loseConnection()

def dataReceived(self, data):


if data == b"READY":
if self.fileData:
self.transport.write(self.fileData)
else:
self.transport.loseConnection()
elif data == b"RECEIVED":
endTime = time.time() # Stop measuring time
rtt = endTime - self.startTime
print("Round trip time:", rtt)
print("File transfer complete.")
self.transport.loseConnection()
else:
print("Error:", data.decode())
self.transport.loseConnection()

class FileTransferClientFactory(protocol.ClientFactory):
protocol = FileTransferClientProtocol

if __name__ == "__main__":
reactor.connectTCP("localhost", 7000, FileTransferClientFactory())
reactor.run()
36 / 73

OUTPUT:
ECHO

CHAT

FILE TRANSFER

RESULT:
The TCP Echo Server and Echo Client for Single Server, Chat Server and File Transfer
applications have been implemented and tested successfully using Twisted Python.
37 / 73

EXERCISE 8: UDP SOCKETS


AIM:
To implement UDP Echo Server and Echo Client for Single Server, Single Client and Single Server,
Multiple Client, Chat Server, and File Transfer Applications using Twisted Python.

PROCEDURE:
ECHO
1. Based on the IP Address and Port Number the connection is established
between the Server and Client.
2. Port Number should be same in Server and Client.
3. Local Host should be specified in Client.
4. Client will have its data echoed back to server.
CHAT
1. Initialize the server with a port number.
2. Create a socket using UDP protocol.
3. Bind the socket to the server's IP address and port number.
4. Create an empty list to store the client addresses.
5. Start a loop to listen for incoming messages:
6. Receive a message from a client.
7. Check if the client address is already in the list of client addresses.
8. If not, add the client address to the list
9. Broadcast the received message to all clients in the list, except the sender.
FILE TRANSFER
1. Initialize the server with a port number.
2. Create a socket using UDP protocol.
3. Bind the socket to the server's IP address and port number.
4. Start a loop to listen for incoming requests:
5. Receive a request from a client
38 / 73

6. Parse the request to identify the FTP command (e.g., LIST, RETR, STOR)
7. Handle the request based on the FTP command:
8. For LIST command, retrieve the directory listing and send it to the client.
9. For RETR command, read the requested file and send it to the client.
10. For STOR command, receive the file from the client and save it on the server
11. Send a response to the client indicating the success or failure of the request.

CODE
ECHO
echoserver.py
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
class EchoUDP(DatagramProtocol):
def datagramReceived(self, datagram, address):
print("Datagram: ",datagram.decode())
self.transport.write(datagram, address)
def main():
reactor.listenUDP(8000, EchoUDP())
print("Started to listen")
reactor.run()

if __name__ == '__main__':
main()

echoclient.py
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import time

class EchoClientDatagramProtocol(DatagramProtocol):
a = input("Enter the message: ")
strings = [f"{a}".encode()]
def startProtocol(self):
self.transport.connect('127.0.0.1', 8000)
self.sendDatagram()
def sendDatagram(self):
if len(self.strings):
datagram = self.strings.pop(0)
self.timestamp = time.time()
self.transport.write(datagram)
else:
39 / 73

reactor.stop()
def datagramReceived(self, datagram, host):
rtt = time.time() - self.timestamp
print('Datagram received: ', datagram.decode(), f"< RTT: {rtt:.4f}s >")
self.sendDatagram()
def main():
protocol = EchoClientDatagramProtocol()
t = reactor.listenUDP(0, protocol)
reactor.run()

if __name__ == '__main__':
main()

CHAT
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
class ChatServer(DatagramProtocol):
def __init__(self):
self.users = {} # maps user addresses to usernames
def datagramReceived(self, data, addr):
message = data.decode('utf-8').strip()
if addr in self.users:
# if the user is already registered, broadcast the message to all other
users
username = self.users[addr]
message = f"<{username}> {message}"
for user_addr in self.users:
if user_addr != addr:
self.transport.write(message.encode('utf-8'), user_addr)
else:
# if the user is not registered, use the first message as their username
self.users[addr] = message.split()[0]
self.transport.write(b"Welcome to the chat!\n", addr)

if __name__ == "__main__":
reactor.listenUDP(5000, ChatServer())
print("Server started.")
reactor.run()
40 / 73

FILE TRANSFER
ftpserver.py
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import pickle
import time
import os

class EchoUDP(DatagramProtocol):
def datagramReceived(self, datagram, address):
receive_time = time.time() # Get the receive timestamp
file_name, file_data, send_time = pickle.loads(datagram)
print(f'{file_name} received!')
rtt = receive_time - send_time # Calculate RTT
print(f'RTT: {rtt} seconds')
file_path = file_name.rstrip('.txt') + 'Server.txt'
with open(file_path, 'wb') as file:
file.write(b'file_data')
file_size = os.path.getsize(file_path) # File size
print(f'{file_name} saved. File size: {file_size} bytes')

def main():
reactor.listenUDP(1234, EchoUDP())
print("UDP server started.")
reactor.run()

if __name__ == '__main__':
main()

ftpclient.py
from __future__ import print_function
import pickle
import time
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class EchoClientDatagramProtocol(DatagramProtocol):
def startProtocol(self):
self.transport.connect('127.0.0.1', 1234)
self.sendDatagram()

def sendDatagram(self):
file_name = input('Enter file name to send: ')
file = open(f'{file_name}', 'r')
file_data = file.read()
send_time = time.time() # Get the send timestamp
41 / 73

data = (file_name, file_data, send_time)


if file_name:
self.transport.write(pickle.dumps(data))
else:
reactor.stop()

def datagramReceived(self, datagram, host):


print('Datagram received:', repr(datagram))
self.sendDatagram()

def main():

protocol = EchoClientDatagramProtocol()
t = reactor.listenUDP(0, protocol)
reactor.run()

if __name__ == '__main__':
main()

OUTPUT:
ECHO

CHAT
42 / 73

FTP

RESULT:
The UDP Echo Server and Echo Client for Single Server, Single Client and Single
Server, Multiple Client, Chat Server and File Transfer applications have been
implemented and tested successfully using Twisted Python
43 / 73

EXERCISE 9: ARP/RARP PROTOCOLS


AIM
To design and develop a Twisted Python application that listens for ARP requests
from devices on the network and enables these devices to dynamically retrieve
their MAC addresses.

PROCEDURE
ARP:
a. Initialize the ARP module.
b. Start a loop to listen for incoming ARP requests:
c. Receive an ARP request packet.
d. Extract the sender's IP and MAC addresses from the request packet.
e. Check if the target IP address matches the IP address of the local host:
f. If yes, construct an ARP response packet with the local host's MAC
address and the sender's IP address.
g. Send the ARP response packet back to the sender.
RARP
1. Initialize the RARP module.
2. Start a loop to listen for incoming RARP requests:
3. Receive a RARP request packet.
4. Extract the sender's MAC address from the request packet.
5. Check if the target MAC address matches the MAC address of the local host
6. If yes, construct a RARP response packet with the local host's IP address.
7. Send the RARP response packet back to the sender
44 / 73

CODE
ARP SERVER
from twisted.internet import reactor, protocol
import struct

class ARPServer(protocol.Protocol):
def connectionMade(self):
print("client connected")

def dataReceived(self, data):


global arp_table
rec = eval(data.decode())
mac_address = '0:0:0:0:0:0'

arp_packet_format = "!6s4s6s4s"
arp_data = struct.unpack(arp_packet_format, rec.get('req_format'))
(
Source_Hardware_Address,
Source_Protocol_Address,
Target_Hardware_Address,
Target_Protocol_Address
) = arp_data

print("Received ARP packet:")


print("Source Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Source_Hardware_Address))
print("Source Protocol Address:", ".".join(str(byte) for byte in
Source_Protocol_Address))
print("Target Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Target_Hardware_Address))
print("Target Protocol Address:", ".".join(str(byte) for byte in
Target_Protocol_Address))

if rec.get('req') == "ARP_REQUEST":
for i in arp_table:
if i == rec.get('ip'):
mac_address = arp_table[i]
else:
continue

l = []
for i in mac_address.split(':'):
l.append(int(i))

ip_address = rec.get('ip')
response_packet = struct.pack(
arp_packet_format,
45 / 73

Target_Hardware_Address,
Target_Protocol_Address,
Source_Hardware_Address,
bytes(l),
)

to_client = {'reply_format': response_packet}

if mac_address != '0:0:0:0:0:0':
arp_reply = f'ARP_REPLY {ip_address} {mac_address}\n'
to_client['data'] = arp_reply
self.transport.write(str(to_client).encode())
print("MAC Address sent")
else:
self.transport.write(b'hi')
print("Invalid IP received")

def connectionLost(self, reason):


print("client removed")
return

class ARPServerFactory(protocol.Factory):
def buildProtocol(self, addr):
return ARPServer()

arp_table = {}
arp_table['192.168.1.1'] = '00:11:22:33:44:55'

reactor.listenTCP(1234, ARPServerFactory())
reactor.run()

ARP CLIENT
from twisted.internet import reactor, protocol
import struct
class ARPClient(protocol.Protocol):
def connectionMade(self):
arp_packet_format = "!6s4s6s4s"
request_packet = struct.pack(
arp_packet_format,
bytes([0, 17, 34, 51, 68, 85]), # Example source hardware address
bytes([0, 0, 0, 0]), # Example source protocol address
bytes([17, 18, 19, 20, 21, 22]), # Example target hardware address
bytes([26, 27, 28, 29]) # Example target protocol address
)
a = input("Enter IP address:")
to_server = {'ip': a, 'req_format': request_packet, 'req': 'ARP_REQUEST'}
self.transport.write(str(to_server).encode())
46 / 73

def dataReceived(self, data):


recv = eval(data.decode())
arp_packet_format = "!6s4s6s4s"
(
Source_Hardware_Address,
Source_Protocol_Address,
Target_Hardware_Address,
Target_Protocol_Address
) = struct.unpack(arp_packet_format, recv.get('reply_format'))

print("Received ARP reply:")


print("Source Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Source_Hardware_Address))
print("Source Protocol Address:", ".".join(str(byte) for byte in
Source_Protocol_Address))
print("Target Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Target_Hardware_Address))
print("Target Protocol Address:", ".".join(str(byte) for byte in
Target_Protocol_Address))

if recv.get('data').startswith('ARP_REPLY'):
reply_parts = recv.get('data').split()
if len(reply_parts) == 3:
mac_address = reply_parts[2]
ip_address = reply_parts[1]
print(f"Received ARP reply: IP = {ip_address}, MAC =
{mac_address}")
self.transport.loseConnection()
else:
print("Invalid ARP reply")
self.transport.loseConnection()
else:
print("Invalid IP Address given!")
self.transport.loseConnection()

class ARPClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return ARPClient()

def clientConnectionFailed(self, connector, reason):


print("Connection failed.")
reactor.stop()

def clientConnectionLost(self, connector, reason):


print("Connection lost.")
reactor.stop()

reactor.connectTCP('localhost', 1234, ARPClientFactory())


reactor.run()
47 / 73

RARP SERVER:
from twisted.internet import reactor, protocol
import struct

class RARPServer(protocol.Protocol):
def connectionMade(self):
print("client connected")

def dataReceived(self, data):


global rarp_table
rec = eval(data.decode())
ip_address = '0.0.0.0'

rarp_packet_format = "!6s4s6s4s"
rarp_data = struct.unpack(rarp_packet_format, rec.get('req_format'))
(
Source_Hardware_Address,
Source_Protocol_Address,
Target_Hardware_Address,
Target_Protocol_Address
) = rarp_data

print("Received RARP packet:")


print("Source Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Source_Hardware_Address))
print("Source Protocol Address:", ".".join(str(byte) for byte in
Source_Protocol_Address))
print("Target Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Target_Hardware_Address))
print("Target Protocol Address:", ".".join(str(byte) for byte in
Target_Protocol_Address))

if rec.get('req') == "RARP_REQUEST":
for i in rarp_table:
if i == rec.get('mac'):
ip_address = rarp_table[i]
else:
continue
l = []
for i in ip_address.split('.'):
l.append(int(i))

mac_address = rec.get('mac')
response_packet = struct.pack(
rarp_packet_format,
Target_Hardware_Address,
Target_Protocol_Address,
Source_Hardware_Address,
48 / 73

bytes(l),
)

to_client = {'reply_format': response_packet}

if ip_address != '0.0.0.0':
rarp_reply = f'RARP_REPLY {mac_address} {ip_address}\n'
to_client['data'] = rarp_reply
self.transport.write(str(to_client).encode())
print("IP Address sent")
else:
self.transport.write(b'hi')
print("Invalid MAC received")

def connectionLost(self, reason):


print("client removed")
return

class RARPServerFactory(protocol.Factory):
def buildProtocol(self, addr):
return RARPServer()

rarp_table = {}
rarp_table['00:11:22:33:44:55'] = '192.168.1.1'

reactor.listenTCP(1234, RARPServerFactory())
reactor.run()

RARP CLIENT
from twisted.internet import reactor, protocol
import struct

class RARPClient(protocol.Protocol):
def connectionMade(self):
rarp_packet_format = "!6s4s6s4s"
request_packet = struct.pack(
rarp_packet_format,
bytes([00, 11, 22, 33, 44, 55]), # Example source hardware address
bytes([0, 0, 0, 0]), # Example source protocol address
bytes([17, 18, 19, 20, 21, 22]), # Example target hardware address
bytes([26, 27, 28, 29]) # Example target protocol address
)
a = input("Enter MAC address:")
to_server = {'mac': a, 'req_format': request_packet, 'req':
'RARP_REQUEST'}
self.transport.write(str(to_server).encode())

def dataReceived(self, data):


49 / 73

recv = eval(data.decode())
rarp_packet_format = "!6s4s6s4s"
(
Source_Hardware_Address,
Source_Protocol_Address,
Target_Hardware_Address,
Target_Protocol_Address
) = struct.unpack(rarp_packet_format, recv.get('reply_format'))

print("Received RARP reply:")


print("Source Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Source_Hardware_Address))
print("Source Protocol Address:", ".".join(str(byte) for byte in
Source_Protocol_Address))
print("Target Hardware Address:", ":".join("{:02x}".format(byte) for byte
in Target_Hardware_Address))
print("Target Protocol Address:", ".".join(str(byte) for byte in
Target_Protocol_Address))

if recv.get('data').startswith('RARP_REPLY'):
reply_parts = recv.get('data').split()
if len(reply_parts) == 3:
mac_address = reply_parts[1]
ip_address = reply_parts[2]
print(f"Received RARP reply: MAC = {mac_address}, IP =
{ip_address}")
self.transport.loseConnection()
else:
print("Invalid RARP reply")
self.transport.loseConnection()
else:
print("Invalid MAC Address given!")
self.transport.loseConnection()

class RARPClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return RARPClient()

def clientConnectionFailed(self, connector, reason):


print("Connection failed.")
reactor.stop()

def clientConnectionLost(self, connector, reason):


print("Connection lost.")
reactor.stop()

reactor.connectTCP('localhost', 1234, RARPClientFactory())


reactor.run()
50 / 73

OUTPUT
ARP

RARP

RESULT
Thus, the simulation of ARP/RARP protocols have been implemented and tested
successfully using Twisted Python.
51 / 73

EXERCISE 10: STOP AND WAIT AND SLIDING


WINDOW
AIM
To write a program to implement the stop and wait protocol using Twisted Python.

PROCEDURE
1. Sender:
• Initialize with sequence number 0.
• Read data and create a packet.
• Send packet to receiver.
• Start timer.
2. Receiver:
• Wait for packet from sender.
• Receive packet.
• If sequence number matches expected, deliver data and send ACK.
• If sequence number doesn't match expected, discard packet and send
NAK.
3. Sender:
• Wait for ACK/NAK.
• If ACK received, stop timer, update sequence number, read new data,
and repeat.
• If NAK received, resend packet and restart timer.
4. Sender:
• If timeout occurs, resend packet and restart timer.
5. Receiver:
• After sending ACK/NAK, return to step 2.
6. Sender:
52 / 73

• After resending or receiving ACK/NAK, return to step 3.


7. Termination:
• Stop sender and receiver when all data is sent and acknowledged.
Sliding window
1. Sender:
• Initialize with sequence numbers for the window.
• Read data and create packets.
• Send packets within the window to receiver.
• Start timer for the oldest unacknowledged packet.
2. Receiver:
• Wait for packets from sender within the window.
• Receive packets and send cumulative ACK for the highest in-order
packet.
• Update the window to slide over received packets.
3. Sender:
• Wait for ACK packets.
• If ACK received, update the window and slide it forward.
• If timeout occurs, retransmit packets in the window.
4. Sender:
• If the last packet in the window is sent, wait for ACK or timeout.
5. Receiver:
• After sending cumulative ACK, return to step 2.
6. Sender:
• After receiving ACK or timeout, return to step 3.
7. Termination:
• Stop sender and receiver when all data is sent, received, and
acknowledged.
53 / 73

CODE
SERVER:
from twisted.internet import reactor, protocol

class StopAndWaitServer(protocol.Protocol):
def connectionMade(self):
print("Client connected:", self.transport.getPeer())
self.send_message()

def send_message(self):
message = input("Enter message: ")
self.transport.write(message.encode())
print("Message sent to client:", message)
self.expected_ack = "ACK"
# self.schedule_resend()

def schedule_resend(self):
self.resend_call = reactor.callLater(5, self.resend_message)

def resend_message(self):
print("ACK not received. Resending message...")
self.send_message()

def dataReceived(self, data):


ack = data.decode()
print("ACK received:", ack)
if ack == self.expected_ack:
# self.resend_call.cancel()
print("ACK received. Message acknowledged.")
self.send_message()
else:
print("Invalid ACK received.")
self.schedule_resend()

def connectionLost(self, reason):


print("Client disconnected:")

class StopAndWaitServerFactory(protocol.Factory):
def buildProtocol(self, addr):
return StopAndWaitServer()

server_port = 8000
factory = StopAndWaitServerFactory()
reactor.listenTCP(server_port, factory)
reactor.run()
54 / 73

CLIENT:
from twisted.internet import reactor, protocol

class StopAndWaitClient(protocol.Protocol):
def connectionMade(self):
print("Connected to server.")
self.send_ack()

def send_ack(self):
self.transport.write(input("Enter ack: ").encode())
print("ACK sent")

def dataReceived(self, data):


message = data.decode()
print("Message received:", message)
self.send_ack()

def connectionLost(self, reason):


print("Connection lost:", reason.getErrorMessage())

class StopAndWaitClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return StopAndWaitClient()

def clientConnectionFailed(self, connector, reason):


print("Connection failed:", reason.getErrorMessage())
reactor.stop()

def clientConnectionLost(self, connector, reason):


print("Connection lost:", reason.getErrorMessage())
reactor.stop()

server_address = 'localhost'
server_port = 8000
factory = StopAndWaitClientFactory()
reactor.connectTCP(server_address, server_port, factory)
reactor.run()
55 / 73

OUTPUTS

STOP AND WAIT

RESULT
Thus, the Stop and Wait and Sliding Window protocols have been implemented
and tested successfully using Twisted Python.
56 / 73

Exercise 11: HTTP CLIENT


AIM:
Implementation of HTTP Web client program to download a web page using TCP
sockets using Twisted Python.

PROCEDURE
o User Input: Obtain the URL of the web page to be downloaded from the
user
o Initialize the program and prepare to download the web page.
o Establish a connection to the web server hosting the requested page.
o Send an HTTP GET request to the server, asking for the contents of the web
page.
o Wait for the server to respond with the requested web page.
o Receive the data in chunks as the server sends them.
o Combine the received chunks of data to form the complete content of the
web page.
o Output the contents of the web page on the screen for the user to see.

CODE :
from twisted.internet import reactor
from twisted.web.client import Agent
from twisted.web.client import readBody
def download_web_page(url):
agent = Agent(reactor)

def handle_response(response):
d = readBody(response) # Read the response body

def process_body(body):
print(body.decode()) # Process the received data
reactor.stop()

d.addCallback(process_body)
return d

def handle_error(error):
print(f"An error occurred: {error}") # Handle any errors
reactor.stop()

d = agent.request(b"GET", url.encode()) # Make an HTTP GET request


57 / 73

d.addCallbacks(handle_response, handle_error)

reactor.run()

if __name__ == "__main__":
download_web_page("http://www.google.com/")

OUTPUT

RESULT
Web page information has successfully been downloaded via HTTP protocol and
implemented using twisted python.
58 / 73

EXERCISE 12: REMOTE PROCEDURE CALL


AIM:
Implementation of Remote Procedure Call (RPC) using Twisted Python.

PROCEDURE
1. Define an interface specifying available functions/methods for remote
invocation.
2. Serialize input parameters and return values for transmission.
3. Deserialize received data to obtain original values.
4. Use a client stub/proxy to invoke remote functions/methods.
5. Implement a server stub/skeleton to handle requests and invoke actual
functions/methods.
6. Utilize an RPC framework to manage communication between client and
server.

CODE
SERVER
from twisted.internet import reactor, protocol

class RPCServerProtocol(protocol.Protocol):
def dataReceived(self, data):
request = data.decode().strip()
result = self.processRequest(request)
self.transport.write(result.encode())

def processRequest(self, request):


# Process the request and return the result
# Replace this with your own server-side logic
if request == "add 10 5":
return str(10 + 5)
else:
return "Invalid request"

class RPCServerFactory(protocol.Factory):
def buildProtocol(self, addr):
return RPCServerProtocol()

if __name__ == "__main__":
59 / 73

reactor.listenTCP(8000, RPCServerFactory())
print("RPC server is running...")
reactor.run()

CLIENT
from twisted.internet import reactor, protocol
class RPCClientProtocol(protocol.Protocol):
def connectionMade(self):
self.transport.write(b"add 10 5")

def dataReceived(self, data):


result = data.decode().strip()
print("Result:", result)
self.transport.loseConnection()

class RPCClientFactory(protocol.ClientFactory):
protocol = RPCClientProtocol

def clientConnectionFailed(self, connector, reason):


print("Connection failed.")
reactor.stop()

def clientConnectionLost(self, connector, reason):


print("Connection lost.")
reactor.stop()
if __name__ == "__main__":
from twisted.internet import endpoints

endpoint = endpoints.TCP4ClientEndpoint(reactor, "localhost", 8000)


factory = RPCClientFactory()
endpoint.connect(factory)

reactor.run()

OUTPUT

RESULT:
RPC has been successfully implemented using twisted python
60 / 73

EXERCISE 13: IMPLEMENTATION OF SUBNETTING


AIM:
To implement subnetting of a network using twisted python

PROCEDURE
1. Create an IPv4Network object representing the desired subnet.
2. Define a protocol class (SubnetCheckerProtocol) that inherits from
twisted.internet.protocol.Protocol.
3. Implement the dataReceived method in the protocol class to handle
incoming data from clients.
4. Parse the received data as an IP address.
5. Check if the IP address falls within the defined subnet.
6. Send a response indicating whether the IP address is within the subnet or
outside.
7. Close the connection.
8. Define a factory class (SubnetCheckerFactory) that inherits from
twisted.internet.protocol.Factory.
9. Implement the buildProtocol method in the factory class to create instances
of the protocol class for each connection.
10.Start the reactor, listening on a specific port, and using the factory to handle
incoming connections.
11.Print a message indicating that the subnet checker server is running.
12.Run the reactor.
CODE:
from twisted.internet import reactor, protocol
import ipaddress

SUBNET = ipaddress.IPv4Network("192.168.0.0/24")

class SubnetCheckerProtocol(protocol.Protocol):
def dataReceived(self, data):
ip_address = data.strip().decode()
if self.is_in_subnet(ip_address):
self.transport.write(b"IP address is within the subnet")
else:
self.transport.write(b"IP address is outside the subnet")
self.transport.loseConnection()

def is_in_subnet(self, ip_address):


61 / 73

try:
ip = ipaddress.IPv4Address(ip_address)
return ip in SUBNET
except ipaddress.AddressValueError:
return False

class SubnetCheckerFactory(protocol.Factory):
def buildProtocol(self, addr):
return SubnetCheckerProtocol()

if __name__ == "__main__":
reactor.listenTCP(8000, SubnetCheckerFactory())
print("Subnet checker server is running...")
reactor.run()

OUTPUT:

RESULT:
An illustration of subnetting has be implemented using Twisted python.
62 / 73

EXERCISE 14: DNS, SMTP, AND SNMP


AIM:
Applications using TCP and UDP Sockets like
a) DNS
b) SNMP
c) SMTP using Twisted Python.

PROCEDURE
DNS
1. Create a server that listens for DNS requests on a specific port.
2. Define a method to handle incoming DNS requests.
3. When a request arrives, read and understand the request.
4. Process the request by performing the necessary logic (e.g., looking up the
IP address associated with the domain name).
5. Prepare a response based on the processing result.
6. Send the response back to the client.
7. Repeat steps 2 to 6 for each new incoming request.

SMTP
1. Set up a server that listens on a specific port (typically port 25) for incoming
connections.
2. Accept incoming client connections.
3. Receive the SMTP commands and email messages from the clients.
4. Parse the commands and messages to extract the necessary information.
5. Perform the appropriate actions based on the received commands (e.g.,
sending acknowledgement, validating recipients, delivering messages).
6. Send back response codes and messages to the client to indicate the status
of the SMTP operation.
7. Repeat steps 3 to 6 for each client connection.
8. Close the connection when the SMTP operation is complete
63 / 73

SNMP
1. The client sends an SNMP GET request to the server.
2. The server receives the request, processes it, and sends an SNMP response
back to the client.
3. Upon receiving the response, the client processes it.
4. The client can then send additional data to the server by using
self.transport.write() within the datagramReceived method.
5. The server receives the additional data and can process it accordingly

CODE:
DNS:
dnsserver.py
from twisted.internet import reactor, protocol

class DNSProtocol(protocol.Protocol):
def dataReceived(self, data):
request = data.strip()
response = self.processRequest(request)
self.transport.write(response)

def processRequest(self, request):


# Replace this logic with your own DNS processing
# Here, we simply return a hardcoded response
if request == b"www.example.com":
return b"192.168.0.1"
else:
return b"Unknown domain"

class DNSFactory(protocol.Factory):
def buildProtocol(self, addr):
return DNSProtocol()

if __name__ == "__main__":
reactor.listenTCP(53, DNSFactory())
print("DNS server is running...")
reactor.run()

dnsclient.py
from twisted.internet import reactor, protocol
64 / 73

class DNSClientProtocol(protocol.Protocol):
def connectionMade(self):
domain = input("Enter a domain name: ")
self.transport.write(domain.encode())

def dataReceived(self, data):


response = data.decode()
print("Response:", response)
self.transport.loseConnection()

class DNSClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return DNSClientProtocol()

def clientConnectionFailed(self, connector, reason):


print("Connection failed.")
reactor.stop()

if __name__ == "__main__":
reactor.connectTCP("localhost", 53, DNSClientFactory())
reactor.run()

SMTP:
smtpserver.py
from twisted.internet import protocol, reactor

class SMTPServerProtocol(protocol.Protocol):
def connectionMade(self):
self.transport.write(b'220 smtp.example.com Simple Mail Transfer Service
Ready\r\n')

def dataReceived(self, data):


request = data.decode().strip()

if request.startswith('HELO') or request.startswith('EHLO'):
self.transport.write(b'250 Hello ' + request.split()[1].encode() +
b', pleased to meet you\r\n')
elif request.startswith('MAIL FROM:'):
self.transport.write(b'250 OK\r\n')
elif request.startswith('RCPT TO:'):
self.transport.write(b'250 OK\r\n')
elif request == 'DATA':
self.transport.write(b'354 Start mail input; end with
<CRLF>.<CRLF>\r\n')
self.state = 'DATA'
elif self.state == 'DATA' and request == '.':
65 / 73

self.transport.write(b'250 OK, message received and queued for


delivery\r\n')
self.state = 'IDLE'
elif request == 'QUIT':
self.transport.write(b'221 Goodbye\r\n')
self.transport.loseConnection()
else:
self.transport.write(b'500 Command not recognized\r\n')

def connectionLost(self, reason):


print('Connection lost:', reason)

class SMTPServerFactory(protocol.Factory):
def buildProtocol(self, addr):
return SMTPServerProtocol()

if __name__ == '__main__':
reactor.listenTCP(25, SMTPServerFactory())
reactor.run()

smtpclient.py

from twisted.internet import protocol, reactor

class SMTPClientProtocol(protocol.Protocol):
def connectionMade(self):
self.sendLine(b'HELO client.example.com')

def dataReceived(self, data):


response = data.decode().strip()
print('Server:', response)

if response.startswith('250'):
self.sendLine(b'MAIL FROM:<john@example.com>')
elif response.startswith('250'):
self.sendLine(b'RCPT TO:<sarah@example.com>')
elif response.startswith('250'):
self.sendLine(b'DATA')
elif response.startswith('354'):
self.sendLine(b'From: john@example.com\r\n'
b'To: sarah@example.com\r\n'
b'Subject: Hello Sarah\r\n'
b'\r\n'
b'Hi Sarah, how are you doing? Just wanted to say
hello!\r\n'
b'.')
66 / 73

elif response.startswith('250'):
self.sendLine(b'QUIT')
elif response.startswith('221'):
self.transport.loseConnection()

def sendLine(self, line):


self.transport.write(line + b'\r\n')

def connectionLost(self, reason):


print('Connection lost:', reason)

class SMTPClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return SMTPClientProtocol()

if __name__ == '__main__':
reactor.connectTCP('localhost', 25, SMTPClientFactory())
reactor.run()

SNMP:
snmpserver.py
from twisted.internet import protocol, reactor

class SMTPServerProtocol(protocol.Protocol):
def connectionMade(self):
self.transport.write(b'220 smtp.example.com Simple Mail Transfer Service
Ready\r\n')

def dataReceived(self, data):


request = data.decode().strip()

if request.startswith('HELO') or request.startswith('EHLO'):
self.transport.write(b'250 Hello ' + request.split()[1].encode() +
b', pleased to meet you\r\n')
elif request.startswith('MAIL FROM:'):
self.transport.write(b'250 OK\r\n')
elif request.startswith('RCPT TO:'):
self.transport.write(b'250 OK\r\n')
elif request == 'DATA':
self.transport.write(b'354 Start mail input; end with
<CRLF>.<CRLF>\r\n')
self.state = 'DATA'
elif self.state == 'DATA' and request == '.':
self.transport.write(b'250 OK, message received and queued for
delivery\r\n')
self.state = 'IDLE'
elif request == 'QUIT':
67 / 73

self.transport.write(b'221 Goodbye\r\n')
self.transport.loseConnection()
else:
self.transport.write(b'500 Command not recognized\r\n')

def connectionLost(self, reason):


print('Connection lost:', reason)

class SMTPServerFactory(protocol.Factory):
def buildProtocol(self, addr):
return SMTPServerProtocol()

if __name__ == '__main__':
reactor.listenTCP(25, SMTPServerFactory())
reactor.run()

smtpclient.py
from twisted.internet import protocol, reactor

class SMTPClientProtocol(protocol.Protocol):
def connectionMade(self):
self.sendLine(b'HELO client.example.com')

def dataReceived(self, data):


response = data.decode().strip()
print('Server:', response)

if response.startswith('250'):
self.sendLine(b'MAIL FROM:<john@example.com>')
elif response.startswith('250'):
self.sendLine(b'RCPT TO:<sarah@example.com>')
elif response.startswith('250'):
self.sendLine(b'DATA')
elif response.startswith('354'):
self.sendLine(b'From: john@example.com\r\n'
b'To: sarah@example.com\r\n'
b'Subject: Hello Sarah\r\n'
b'\r\n'
b'Hi Sarah, how are you doing? Just wanted to say
hello!\r\n'
b'.')
elif response.startswith('250'):
self.sendLine(b'QUIT')
elif response.startswith('221'):
self.transport.loseConnection()
68 / 73

def sendLine(self, line):


self.transport.write(line + b'\r\n')

def connectionLost(self, reason):


print('Connection lost:', reason)

class SMTPClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return SMTPClientProtocol()

if __name__ == '__main__':
reactor.connectTCP('localhost', 25, SMTPClientFactory())
reactor.run()

OUTPUT:
DNS

SMTP

SNMP

RESULT
DNS, SMTP using TCP and SNMP using UDP have been implemented with Twisted
python
69 / 73

EXCERCISE 15: NETWORK SIMULATOR


AIM:
To explore and understand the Network Simulator (NS) and its capabilities for
simulating network behaviour. Furthermore, the report focuses on the
simulation of Congestion Control Algorithms using NS to evaluate their
effectiveness in managing network congestion.

PROCEDURE
Network Simulator (NS):
Network Simulator (NS) is an open-source discrete event network simulator
that is widely used for simulating network protocols, traffic, and behaviour. NS
provides a comprehensive environment for designing, implementing, and
evaluating network models. It allows researchers and network engineers to
experiment with various scenarios and study the performance of network
protocols and algorithms.

Simulation of Congestion Control Algorithms:


Congestion control algorithms are crucial for managing network traffic and
ensuring efficient data transmission. Simulating these algorithms using NS
allows researchers to evaluate their performance and compare different
approaches. By replicating real-world network conditions, NS enables the
analysis of congestion control mechanisms under varying scenarios, network
topologies, and traffic patterns.

Steps for Simulation:


Designing the Network Topology: Define the network topology, including
routers, links, and nodes, to replicate the desired network environment. -
Configuring Traffic Patterns: Specify the traffic patterns and data flows to
generate realistic network traffic.

Implementing Congestion Control Algorithms: Develop or select congestion


control algorithms to be simulated within the NS environment. - Running
Simulations: Execute the NS simulation to observe the behaviour of the
congestion control algorithms under different conditions. - Performance
Evaluation: Analyse the simulation results to measure and compare the
performance of the congestion control algorithms based on predefined metrics
such as throughput, delay, packet loss, etc.
70 / 73

Results and Findings: The simulation results obtained from NS provide insights
into the behaviour and effectiveness of various congestion control algorithms.
By comparing different algorithms, researchers can identify their strengths and
weaknesses, enabling them to make informed decisions regarding their
deployment in real-world networks. The results may reveal the impact of
network parameters, traffic patterns, and other factors on the performance of
congestion control mechanisms.

RESULT
Study of Network simulation and congestion control has been performed and
concepts of congestion control have been understood.
71 / 73

EXERCISE 16: ROUTING ALGORITHMS


AIM:
To implement flooding algorithm using twisted python.

PROCEDURE
1. Initialize the protocol with a node ID.
2. Handle connection events (connection made, lost, and data received).
3. Implement the flooding mechanism to send messages periodically to
neighbours.
4. Provide methods to manage neighbours and protocol lifecycle.
5. Set the server and client node IDs.
6. Create protocol instances for the server-side and client-side.
7. Run the server using reactor.listenTCP with the port number and the server
protocol instance.
8. Run the client using reactor.connectTCP with the server's IP address, port
number, and the client protocol instance.
9. Start the event loop with reactor.run().

CODE:
{server side}

from twisted.internet import reactor, protocol

class FloodingProtocol(protocol.Protocol):
def __init__(self, node_id):
self.node_id = node_id
self.neighbors = []

def connectionMade(self):
print(f"Node {self.node_id} connected to the network.")
self.startFlooding()

def connectionLost(self, reason):


print(f"Node {self.node_id} disconnected from the network.")

def dataReceived(self, data):


message = data.decode()
print(f"Node {self.node_id} received message: {message}")

def sendMessage(self, message):


72 / 73

for neighbor in self.neighbors:


self.transport.write(message.encode(), neighbor)

def startFlooding(self):
message = f"Hello from Node {self.node_id}"
self.sendMessage(message)
reactor.callLater(1, self.startFlooding)

def addNeighbor(self, neighbor):


self.neighbors.append(neighbor)

def removeNeighbor(self, neighbor):


if neighbor in self.neighbors:
self.neighbors.remove(neighbor)

def startProtocol(self):
pass

def stopProtocol(self):
reactor.stop()
class FloodingFactory(protocol.Factory):
def __init__(self, node_id):
self.node_id = node_id

def buildProtocol(self, addr):


return FloodingProtocol(self.node_id)

if __name__ == "__main__":
node_id = "A" # Replace with the ID of the current node
factory = FloodingFactory(node_id)
reactor.listenTCP(8000, factory) # Replace with the desired port number
reactor.run()

{client side}

from twisted.internet import reactor, protocol

class FloodingClient(protocol.Protocol):
def __init__(self, node_id):
self.node_id = node_id

def connectionMade(self):
print(f"Client {self.node_id} connected to the server.")
self.sendMessage()

def dataReceived(self, data):


message = data.decode()
print(f"Client {self.node_id} received message: {message}")
73 / 73

def sendMessage(self):
message = f"Hello from Client {self.node_id}"
self.transport.write(message.encode())

def connectionLost(self, reason):


print(f"Client {self.node_id} disconnected from the server.")

def startProtocol(self):
pass

def stopProtocol(self):
reactor.stop()
class FloodingClientFactory(protocol.ClientFactory):
def __init__(self, node_id):
self.node_id = node_id

def buildProtocol(self, addr):


return FloodingClient(self.node_id)

def clientConnectionFailed(self, connector, reason):


print(f"Connection failed for Client {self.node_id}:
{reason.getErrorMessage()}")
reactor.stop()

def clientConnectionLost(self, connector, reason):


print(f"Connection lost for Client {self.node_id}:
{reason.getErrorMessage()}")
reactor.stop()

if __name__ == "__main__":
node_id = "C" # Replace with the ID of the client node
factory = FloodingClientFactory(node_id)
reactor.connectTCP("localhost", 8000, factory) # Replace with the IP address
and port of the server
reactor.run()

OUTPUT

RESULT
Flooding algorithm has been successfully implemented using twisted python.

You might also like