0% found this document useful (0 votes)
16 views14 pages

Exps. 1-4 CN - DCN

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

ns.

py: A Pythonic Discrete-Event Network Simulator


This discrete-event network simulator is based on simpy, which is a general-purpose discrete event simulation
framework for Python. ns.py is designed to be flexible and reusable, and can be used to connect multiple
networking components together easily, including packet generators, network links, switch elements,
schedulers, traffic shapers, traffic monitors, and demultiplexing elements.

Installation

First, launch the PyCharm IDE terminal, and install simpy and ns.py using pip:

$ pip install simpy


$ pip install ns.py

That's it! To upgrade Python packages in the current environment, run the command:

$ python upgrade_packages.py

Current network components

The network components that are included are:

Packet: a simple representation of a network packet, carrying its creation time, size, packet id, flow id, source and
destination.
DistPacketGenerator: generates packets according to provided distributions of inter-arrival times and packet sizes.
TracePacketGenerator: generates packets according to a trace file, with each row in the trace file representing a packet.
TCPPacketGenerator: generates packets using TCP as the transport protocol.
ProxyPacketGenerator: redirects real-world packets (with fixed packet sizes) into the simulation environment.
PacketSink: receives packets and records delay statistics.
TCPSink: receives packets, records delay statistics, and produces acknowledgements back to a TCP sender.
ProxySink: redirects all received packets to a destination real-world TCP server.
Port: an output port on a switch with a given rate and buffer size (in either bytes or the number of packets), using the
simple tail-drop mechanism to drop packets.
REDPort: an output port on a switch with a given rate and buffer size (in either bytes or the number of packets), using the
Early Random Detection (RED) mechanism to drop packets.
Wire: a network wire (cable) with its propagation delay following a given distribution. There is no need to model the
bandwidth of the wire, as that can be modeled by its upstream Port or scheduling server.
Splitter: a splitter that simply sends the original packet out of port 1 and sends a copy of the packet out of port 2.
NWaySplitter: an n-way splitter that sends copies of the packet to n downstream elements.
TrTCM: a two rate three color marker that marks packets as green, yellow, or red (refer to RFC 2698 for more details).
RandomDemux: a demultiplexing element that chooses the output port at random.
FlowDemux: a demultiplexing element that splits packet streams by flow ID.
FIBDemux: a demultiplexing element that uses a Flow Information Base (FIB) to make packet forwarding decisions based on
flow IDs.
TokenBucketShaper: a token bucket shaper.
TwoRateTokenBucketShaper: a two-rate three-color token bucket shaper with both committed and peak rates/burst sizes.
SPServer: a Static Priority (SP) scheduler.
WFQServer: a Weighted Fair Queueing (WFQ) scheduler.
DRRServer: a Deficit Round Robin (DRR) scheduler.
VirtualClockServer: a Virtual Clock scheduler.
SimplePacketSwitch: a packet switch with a FIFO bounded buffer on each of the outgoing ports.
FairPacketSwitch: a fair packet switch with a choice of a WFQ, DRR, Static Priority or Virtual Clock scheduler, as well as
bounded buffers, on each of the outgoing ports. It also shows an example how a simple hash function can be used to map
tuples of (flow_id, node_id, and port_id) to class IDs, and then use the parameter flow_classes to activate class-based
scheduling rather than flow_based scheduling.
1
PortMonitor: records the number of packets in a Port. The monitoring interval follows a given distribution.
ServerMonitor: records performance statistics in a scheduling server, such as WFQServer, VirtualClockServer, SPServer,
or DRRServer.

Writing new network components

To design and implement new network components in this framework, you will first need to read the 10-minute SimPy tutorial. It
literally takes 10 minutes to read, but if that is still a bit too long, you can safely skip the section on Process Interaction, as this feature
will rarely be used in this network simulation framework.

In the Basic Concepts section of this tutorial, pay attention to three simple calls: env.process(), env.run(), and yield
env.timeout(). These are heavily used in this network simulation framework.

Setting up a process

The first is used in our component's constructor to add this component's run() method to the SimPy environment. For example,
in scheduler/drr.py:

self.action = env.process(self.run())
Keep in mind that not all network components need to be run as a SimPy process (more discussions on processes later). While traffic
shapers, packet generators, ports (buffers), port monitors, and packet schedulers definitely should be implemented as processes, a
flow demultiplexer, a packet sink, a traffic marker, or a traffic splitter do not need to be modeled as processes. They just represent
additional processing on packets inside a network.

Running a process

The second call, env.run(), is used by our examples to run the environment after connecting all the network components together.
For example, in examples/drr.py:

env.run(until=100)
This call simply runs the environment for 100 seconds.

Scheduling an event

The third call, yield env.timeout(), schedules an event to be fired sometime in the future. SimPy uses an ancient feature in Python
that's not well known, generator functions, to implement what it called processes. The term process is a bit confusing, as it has nothing
to do with processes in operating systems. In SimPy, each process is simply a sequence of timed events, and multiple processes occur
concurrently in real-time. For example, a scheduler is a process in a network, and so is a traffic shaper. The traffic shaper runs
concurrently with the scheduler, and both of these components run concurrently with other traffic shapers and schedulers in other
switches throughout the network.

In order to implement these processes in a network simulation, we almost always use the yield env.timeout() call.
Here, yield uses the feature of generator functions to return an iterator, rather than a value. This is just a fancier way of saying that
it yields the process in SimPy, allowing other processes to run for a short while, and it will be resumed at a later time specified by the
timeout value. For example, for a Deficit Round Robin (DRR) scheduler to send a packet (in scheduler/drr.py), it simply calls:

yield self.env.timeout(packet.size * 8.0 / self.rate)


which implies that the scheduler process will resume its execution after the transmission time of the packet elapses. A side note: in
our network components implemented so far, we assume that the rate (or bandwidth) of a link is measured in bits per second, while
everything else is measured in bytes. As a result, we will need a little bit of a unit conversion here.

What a coincidence: the yield keyword in Python in generator functions is the same as the yield() system call in an operating
system kernel! This makes the code much more readable: whenever a process in SimPy needs to wait for a shared resource or a
timeout, simply call yield, just like calling a system call in an operating system.

2
Experiment - 1

Aim To implement a Client-Server model using Python socket library.

Theory

A socket client requests for some resources to the socket server and the server responds to that request. So we
will design both server and client model so that each can communicate with them. The steps can be
considered like this -

Python socket server program executes at first and wait for any request.
Python socket client program will initiate the conversation at first.
Then server program will response accordingly to client requests.
Client program will
when client program terminates, this is optional and we can keep server program running
indefinitely or terminate with some specific command in client request.

Python Socket Server - We will save python socket server program as socket_server.py. To use python socket
connection, we need to import socket module. Then, sequentially we need to perform some task to establish
connection between server and client. We can obtain host address by using socket.gethostname() function. It
is recommended to user port address above 1024 because port number lesser than 1024 are reserved for
standard internet protocol. So our python socket server is running on port 5000 and it will wait for client
request

Python Socket Client - We will save python socket client program as socket_client.py. This program is
similar to the server program, except binding. The main difference between server and client program is, in
server program, it needs to bind host address and port address together.

(Ref- https://www.digitalocean.com/community/tutorials/python-socket-programming-server-client)

Python Script (socket_client.py)


# This program is similar to the server program, except binding.
# The main difference between server and client program is,
# in server program, it needs to bind host address and port address together.

import socket
def client_program():
host = socket.gethostname() # as both code is running on same pc

3
port = 5000 # socket server port number

client_socket = socket.socket() # instantiate


client_socket.connect((host, port)) # connect to the server.
# Notice that socket server is running on port 5000
# but client also requires a socket port to connect to the server.

#57822.

message = input(" -> ") # take input

while message.lower().strip() != 'bye':


client_socket.send(message.encode()) # send message
data = client_socket.recv(1024).decode() # receive response

print('Received from server: ' + data) # show in terminal

message = input(" -> ") # again take input

client_socket.close() # close the connection

if __name__ == '__main__':
client_program()

Python Script (socket_server.py)


import socket
def server_program():
# get the hostname
host = socket.gethostname()
port = 5000 # initiate port no above 1024. It is recommended to user port
#address above 1024
# because port number lesser than 1024 are reserved for standard internet
# protocol.

4
server_socket = socket.socket() # get instance
# look closely. The bind() function takes tuple as argument
server_socket.bind((host, port)) # bind host address and port together

# configure how many client the server can listen simultaneously


server_socket.listen(2)
conn, address = server_socket.accept() # accept new connection
print("Connection from: " + str(address))
while True:
# receive data stream. it won't accept data packet greater than 1024
#bytes
data = conn.recv(1024).decode()
if not data:
# if data is not received break
break
print("from connected user: " + str(data))
data = input(' -> ')
conn.send(data.encode()) # send data to the client

conn.close() # close the connection

if __name__ == '__main__':
server_program()

#To see the output, first run the socket server program. Then run the socket client program. After that, write
something from client program. Then again write reply from server program. At last, write bye from client
program to terminate both programs.

5
Client-Server model using Cisco Packet Tracer

6
Experiment - 2

Aim To implement a Star Topological Network using a Hub and Switch.

Required- Cisco Packet Tracer

7
# The following program generates a hybrid topological network based on Star &
Mesh topology, and uses Dijkstra's algorithm to find the shortest path in a
weighted and unweighted network.
import networkx as nx
import pylab as pl
g = nx.Graph()
g.add_edge('a', 'b', weight=0.1)
g.add_edge('b', 'c', weight=1.5)
g.add_edge('a', 'c', weight=1.0)
g.add_edge('c', 'd', weight=2.2)
pos = nx.spring_layout(g)
nx.draw_networkx_nodes(g, pos)
nx.draw_networkx_edges(g, pos)
nx.draw_networkx_labels(g, pos)
pl.show()
print(nx.shortest_path(g, 'b', 'd'))
print(nx.shortest_path(g, 'b', 'd', weight = 'weight'))

Output

8
['b', 'c', 'd']
['b', 'a', 'c', 'd']

Process finished with exit code 0

9
Experiment - 3

Aim TCP Packet Generation and reception using ns.py and simpy packages in a Two-hop network.

Theory

Python Script

# A basic example that showcases how TCP can be used to generate packets, and how a TCP sink
# can send acknowledgment packets back to the sender in a simple two-hop network.
# (Refer ns.py/examples/tcp.py at main · TL-System/ns.py · GitHub)
# Install simpy using pip, and import
import simpy
# Install ns.py using pip
from ns.flow.cc import TCPReno
from ns.flow.cubic import TCPCubic
from ns.flow.flow import AppType, Flow
from ns.packet.tcp_generator import TCPPacketGenerator
from ns.packet.tcp_sink import TCPSink
from ns.port.wire import Wire
from ns.switch.switch import SimplePacketSwitch

def packet_arrival():
"""Packets arrive with a constant interval of 0.1 seconds."""
return 0.1

def packet_size():
"""The packets have a constant size of 1024 bytes."""
return 512

10
def delay_dist():
"""Network wires experience a constant propagation delay of 0.1 seconds."""
return 0.1

env = simpy.Environment()

flow = Flow(
fid=0,
src="flow 1",
dst="flow 1",
finish_time=10,
arrival_dist=packet_arrival,
size_dist=packet_size,
)

sender = TCPPacketGenerator(
env, flow=flow, cc=TCPReno(), element_id=flow.src, debug=True
)

wire1_downstream = Wire(env, delay_dist)


wire1_upstream = Wire(env, delay_dist)
wire2_downstream = Wire(env, delay_dist)
wire2_upstream = Wire(env, delay_dist)

switch = SimplePacketSwitch(
env,
nports=2,
port_rate=16384, # in bits/second
buffer_size=5, # in packets
debug=True,
)

11
receiver = TCPSink(env, rec_waits=True, debug=True)

sender.out = wire1_downstream
wire1_downstream.out = switch
wire2_downstream.out = receiver
receiver.out = wire2_upstream
wire2_upstream.out = switch

fib = {0: 0, 10000: 1}


switch.demux.fib = fib
switch.demux.outs[0].out = wire2_downstream
switch.demux.outs[1].out = wire1_upstream

wire1_upstream.out = sender

env.run(until=100)

Output
..
.
.
Average throughput (last 10 packets): 2048.00 bytes/second.
Queue length at port: 0 packets.
TCPPacketGenerator flow 1 received ack till sequence number 35328 at time
39.1879.
TCPPacketGenerator flow 1 congestion window size = 1536.0, last ack = 35328.
TCPPacketGenerator flow 1 stopped timer 34816 at time 39.1879.

Process finished with exit code 0

12
Experiment - 4

Aim TCP Packet Generation and reception using SimComponents.py user-defined library and simpy
package in a Two-hop network.

Theory

Python Script

# Two-hop TCP Packet Generator using SimComponents.py user-defined library

from random import expovariate


import simpy

# Install SimComponents.py or download from Discrete Event Simulation for Networking with
Python (grotto-networking.com)
from SimComponents import PacketGenerator, PacketSink

def constArrival(): # Constant arrival distribution for generator 1


return 1.5

def constArrival2():
return 2.0

def distSize():
return expovariate(0.01)

env = simpy.Environment() # Create the SimPy environment


# Create the packet generators and sink
ps = PacketSink(env, debug=True) # debugging enable for simple output
pg = PacketGenerator(env, "HELLO", constArrival, distSize)
pg2 = PacketGenerator(env, "BYE", constArrival2, distSize)
# Wire packet generators and sink together
pg.out = ps

1
pg2.out = ps
env.run(until=20)

Output
id: 1, src: HELLO, time: 1.5, size: 34.356269396815556

id: 1, src: BYE, time: 2.0, size: 28.754724325432782

id: 2, src: HELLO, time: 3.0, size: 221.82735422740106

id: 2, src: BYE, time: 4.0, size: 7.9241523544784

id: 3, src: HELLO, time: 4.5, size: 17.865941038477985

id: 3, src: BYE, time: 6.0, size: 46.57571735969745

id: 4, src: HELLO, time: 6.0, size: 82.83519216726376

id: 5, src: HELLO, time: 7.5, size: 21.610321474040532

id: 4, src: BYE, time: 8.0, size: 93.99750184539823

id: 6, src: HELLO, time: 9.0, size: 63.74519382354079

id: 5, src: BYE, time: 10.0, size: 156.20089395687148

id: 7, src: HELLO, time: 10.5, size: 37.486336202923255

id: 6, src: BYE, time: 12.0, size: 38.34828474517665

id: 8, src: HELLO, time: 12.0, size: 30.869258569919914

id: 9, src: HELLO, time: 13.5, size: 107.32918479040028

id: 7, src: BYE, time: 14.0, size: 90.5537670628039

id: 10, src: HELLO, time: 15.0, size: 145.2831943053056

id: 8, src: BYE, time: 16.0, size: 44.57596556710391

id: 11, src: HELLO, time: 16.5, size: 56.70276033249427

id: 9, src: BYE, time: 18.0, size: 3.1399124971569283

id: 12, src: HELLO, time: 18.0, size: 491.6830175467549

id: 13, src: HELLO, time: 19.5, size: 171.36901108282404

Process finished with exit code 0

You might also like