Created
March 16, 2020 02:01
-
-
Save evscott/91629e39842e7595344d521a7402c375 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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