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()