Stop and Wait protocol is a data link layer protocol for transmission of data over noiseless channels. It is a flow control protocol used in noiseless channels. In this article we would code a Python program to implement the stop and wait protocol using sockets and threading.
You can use any code editor you want to run this program. However, using VS Code is recommended.
Let’s look at the sender’s side (the receiver side code can be found here)
#make necessary imports
import socket
from threading import *
import time
import random
#------------------------------------------------------------------------
#create socket object and bind it.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "localhost"
port = 8000
s.bind((host, port))
#------------------------------------------------------------------------
#defines the class for client.
class client(Thread):
#initialize everything
def __init__(self, socket, address):
Thread.__init__(self)
self.sock = socket
self.addr = address
self.start()
def run(self):
while True:
#take input from user
bitstring = str(input("enter bit string"))
propogationtime = float(input("enter propogation time"))
p_nosend = float(input("enter probability of message getting lost:"))
#create a list of 1000 elements. (redundant, can be changed)
l = []
for i in range(0,1000):
l = l +[i]
#go through all the bits of the bitstring.
i = 0
while i < len(bitstring):
#for each bit, create a dictionary with the current
#window index (i%2 => 0,1,0,1...) and the bit itself
datadict = {}
datadict = {i%2 : bitstring[i], }
#convert the dictionary to a string
sendstring_str = str(datadict)
sendstring = bytes(sendstring_str, 'utf-8')
print(sendstring)
#find a random number between 0,1000 (both included)
number= random.randint(0,1000)
#store current time
time1 = time.time()
#if statement is true with a probability of (1-p_nosend)
if l[number] < (p_nosend*1000):
#if true, send the bitstring.
clientsocket.send(sendstring)
#sleep to simulate the propogation time of the channel.
time.sleep((propogationtime)/1.1)
#after sleeping, record the current time.
time2 = time.time()
#this flag indicates whether an acknowledgement has been received.
ackflag= False
#else statement is true with a probability of (p_nosend)
#this simulates a packet being sent but getting lost
#along the way
else:
#imaginary send line here.
#wait for propogation time again.
time.sleep(propogationtime/1.1)
#record current time
time2 = time.time()
#for info of user:
print ("package dropped 1")
#set ack flag to False, again.
ackflag= False
while True:
#if the time elapsed is less that prop time,
if time2-time1<= propogationtime:
#store current time
time2= time.time()
#set timeout to listen for an acknowledgement.
clientsocket.settimeout(propogationtime/1.1)
#raises exception when the timeout occurs.
try:
#attempt to listen for ack.
recieved = clientsocket.recv(1024)
print(recieved)
if recieved:
print("ack received")
i = i+1
ackflag = True
break
#this occurs when listening has timed out.
except:
#recheck if it has timed out (quite redundant):
if time2 - time1 >propogationtime and ackflag == False:
print ("timeout")
#at this stage, we again simulate a package drop
#with prob p_nosend
number= random.randint(0,1000)
#package sent
if l[number] < (p_nosend*1000):
clientsocket.send(sendstring)
time1 = time.time()
time2 = time.time()
print("package sent")
#package dropped:
else:
time1 = time.time()
time2 = time.time()
#time.sleep(propogationtime/1.1)
print("package dropped 2")
s.listen(5)
print ('Sender ready and is listening')
while (True):
#to accept all incoming connections
clientsocket, address = s.accept()
print("Receiver "+str(address)+" connected")
#create a different thread for every
#incoming connection
client(clientsocket, address)
For the receiver side of the code, go here.
For the github repository for this protocol, click here.