Skip to content

Instantly share code, notes, and snippets.

@evscott
Created March 16, 2020 02:01
Show Gist options
  • Save evscott/91629e39842e7595344d521a7402c375 to your computer and use it in GitHub Desktop.
Save evscott/91629e39842e7595344d521a7402c375 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
# receiver.py
#
# Go-Back-N simulation based on the RDT 2.2 protocol described in
# section 3.4.1 of Computer Networking: A Top-Down Approach, Kurose-Ross, 7th edition
#
import sys
from sm import StateMachine
import rdtlib
from rdtlib import udt_send, rdt_rcv, deliver_data, make_pkt, extract, iscorrupt
expectedSeqNum = 0
# Handle the receiver's 'Wait for call from below' states
#
# There are three cases to handle for each of these:
# 1. Packet is corrupt
# 2. Packet is out-of-sequence
# 3. Packet is OK
def receiver_wait_below():
global expectedSeqNum
print 'Receiver in state WAIT_BELOW'
packet = rdt_rcv()
if iscorrupt(packet):
packet = make_pkt(type=ACK, seq=expectedSeqNum-1)
print 'Receiver: corrupt packet, sending ACK ', expectedSeqNum-1, " ", packet
udt_send(packet)
return 'WAIT_BELOW'
else if not hasSeq(packet, expectedSeqNum):
packet = make_pkt(type=ACK, seq=expectedSeqNum-1)
print 'Receiver: wrong seq num, expected ', expectedSeqNum, ', sending ACK'
udt_send(packet)
return 'WAIT_BELOW'
else:
# OK, transition to waiting for packet with seq=1
data = extract(packet)
deliver_data(data)
packet = make_pkt(type=ACK, seq=expectedSeqNum)
print 'Receiver: packet OK, sending ACK ',expectedSeqNum, packet
expectedSeqNum +=1
udt_send(packet)
return 'WAIT_BELOW'
def ReceiverDone():
pass
#
# Set up the state machine
#
def start_receiver():
receiver = StateMachine('receiver')
receiver.add_state('WAIT_BELOW', receiver_wait_below)
receiver.add_state('R_END', ReceiverDone, end_state=1)
receiver.set_initial_state('WAIT_BELOW')
receiver.run()
rdtlib.peer = ('10.0.0.1', 12002)
start_receiver()
#!/usr/bin/python
#
# Sender
#
#
# Simulation of the RDT 2.2 protocol described in
# section 3.4.1 of Computer Networking: A Top-Down Approach, Kurose-Ross, 7th edition
#
import sys
from Queue import Queue
from sm import StateMachine
import rdtlib
from rdtlib import rdt_send, udt_send, isACK, iscorrupt, rdt_rcv
nextSeqNum = 0
base = 0
windowSize = 4
lastsndpkt = [None, None, None, None] # Holds last sent packet in case it needs to be retransmitted
sent = 0
retrans = 0
# Set up a queue of packets to send
sendbuf = Queue()
for i in 'ABCDEFGHIJ':
sendbuf.put(i)
# Handle the sender's 'Wait for call from above' state
def sender_wait_above():
global lastsndpkt, sent, nextSeqNum, retrans
print 'Sender in state WAIT_ABOVE'
# Determine whether to retransmit packet depending on RDT transmission window and wait
#
# If a packet in the transmission window is marked as having not been sent, retransmit
#
# If send buffer is not empty and the next sequence number of a packet to be sent is
# within the transmission window, then resend
#
# Wait for a ACK response
for i in range(windowSize):
if lastsndpkt[i] != None:
print 'Retransmitting', lastsndpkt[i]
udt_send(lastsndpkt[i])
retrans += 1
elif not sendbuf.empty() and nextSeqNum < base+windowSize:
lastsndpkt[i] = rdt_send(sendbuf.get(), nextSeqNum)
sent += 1
nextSeqNum += 1
else:
lastsndpkt[i] = None
return 'WAIT_ACK'
# Handle 'Wait for ACK' states
def sender_wait_ack():
global lastsndpkt, retrans, nextSeqNum, base
print 'Sender in state WAIT_ACK'
prevBase = base
# Receive and handle packet
#
# Indicate whether packet was either lost in transit or arrived corrupt and print
#
# If base < 10 and the packet was sent successfully (duplicate or not) then
# reset the base to sent packets seq. number+1
#
# If base = 10, then end sender
for i in range(windowSize):
if base == 10:
return 'S_END'
packet = rdt_rcv(timeout=2)
if packet == None:
print 'Sender: Timeout, for packet', nextSeqNum-windowSize+i
elif iscorrupt(packet):
print 'Sender: Corrupt ACK, for packet', nextSeqNum-windowSize+i
elif not isACK(packet, prevBase+j):
print 'Sender: Duplicate ACK, for packet', packet[0][1]
base = packet[0][1]+1
break
else:
base = packet[0][1]+1
# Reset packet transmission history of RDT transmission window
for i in range(windowSize):
windowShift = base - prevBase + i
if windowShift >= windowSize:
lastsndpkt[i] = None
else:
lastsndpkt[i] = lastsndpkt[windowShift]
return 'WAIT_ABOVE'
def SenderDone():
print 'Send buffer empty, exiting'
print 'Sent: ', sent
print 'Retransmitted: ', retrans
#
# Set up the state machine
#
def start_sender():
sender = StateMachine('sender')
sender.add_state('WAIT_ABOVE', sender_wait_above)
sender.add_state('WAIT_ACK', sender_wait_ack)
sender.add_state('S_END', SenderDone, end_state=1)
sender.set_initial_state('WAIT_ABOVE')
sender.run()
rdtlib.peer = ('10.0.0.2', 12002)
start_sender()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment