123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- from packet import packet
- import socket, sys, os, threading
- # save values needed to talk to host emulator
- haddr = sys.argv[1] # network host address
- dport = int(sys.argv[2]) # dest port on host
- rport = int(sys.argv[3]) # recv port for this app
- msg = sys.argv[4] # filename to be sent
- # logfiles (segnums and acks, respectively)
- # at end call things.close()
- seglog = open("segnum.log", "a")
- acklog = open("ack.log", "a")
- # some config vars
- winsize = 10 # window size
- tmout = 0.2 # tmout limit in s
- lock = threading.Lock() # used to avoid thread synch issues
- cv = threading.Condition(lock) # used to let our threads sleep when not needed
- timer = None # will be used for timing packet sendtimes
- first = 0 # first packet in the window
- confirmed = 0 # total confirmed packets for the current file
- snum = 0 # current number we want to send (sequence number, that is)
- char_limit = 500 # max num of characters in one packet's data field
- packets = [] # list to be turned into a list of packets
- total_packets = 0 # total number of packets
- waking = False # flag if the receiver is waking the sender thread
- pack_size = 512 # packet size in bytes
- # try opening the file
- try:
- msgfile = open(msg, 'r')
- except IOError:
- sys.stderr.write("Failed to open file. Stop being terrible at life pls")
- raise SystemExit
- # create packets list
- while(True):
- string = msgfile.read(char_limit)
- if (not string):
- break
- packets.append(packet.create_packet(total_packets, string))
- total_packets += 1
-
- # make winsize not bigger than the file allows
- winsize = min(winsize, total_packets)
- # create socket
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- sock.bind(('', rport))
- # start receiver thread
- # receiver function
- def receiver():
- global confirmed
- global waking
-
- while(True):
- # get a packet, turn into packet type
- pack, addr = sock.recvfrom(pack_size)
- newpacket = packet.parse_udp_data(pack)
-
- lock.acquire()
- # what type is this?
- if (newpacket.type == 2): # EOT
- acklog.write(str(newpacket.seq_num) + "\n")
- lock.release()
- return
- elif (newpacket.type == 1): # data
- lock.release()
- sys.stderr.write("Got data from receiver. Exiting")
- raise SystemExit
- else: # ACK packet
- acklog.write(str(newpacket.seq_num) + "\n")
- if (newpacket.seq_num >= confirmed): # new ACK
- confirmed = newpacket.seq_num + 1
- waking = True
- cv.notify_all()
-
- lock.release()
-
-
- recthread = threading.Thread(target=receiver, args=())
- #recthread.dameon = True
- recthread.start()
-
- # let's get this bread! I mean send some packets
- while (confirmed < total_packets):
- lock.acquire()
-
- # while we have room for packets in the window, send some
- while(snum < confirmed + winsize and snum < total_packets):
- sock.sendto(packets[snum].get_udp_data(), (haddr, dport))
- seglog.write(str(snum) + "\n")
- snum += 1
-
- # use cv to sleep for 0.2s, or if woken up
- cv.wait(tmout) # we get lock back when this returns
-
- # check if we woke from timer or not (status of waking flag)
- # this means we were woken by an ACK.
- if (waking):
- # logic to deal with ACKS deal with in receiver
- waking = False
- else: # we need to reset window
- snum = confirmed + 1 # reset to first unconfirmed packet
- waking = False
-
- # ensure we don't overflow due to window reaching the end
- winsize = min(winsize, total_packets - confirmed)
- lock.release()
- # send EOT to receiver before closing
- sock.sendto(packet.create_eot(snum).get_udp_data(), (haddr, dport))
- recthread.join()
- sock.close()
- # cleanup for testing
- seglog.close()
- acklog.close()
|