sender.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. from packet import packet
  2. import socket, sys, os, threading
  3. # save values needed to talk to host emulator
  4. haddr = sys.argv[1] # network host address
  5. dport = int(sys.argv[2]) # dest port on host
  6. rport = int(sys.argv[3]) # recv port for this app
  7. msg = sys.argv[4] # filename to be sent
  8. # logfiles (segnums and acks, respectively)
  9. # at end call things.close()
  10. seglog = open("segnum.log", "a")
  11. acklog = open("ack.log", "a")
  12. # some config vars
  13. winsize = 10 # window size
  14. tmout = 0.2 # tmout limit in s
  15. lock = threading.Lock() # used to avoid thread synch issues
  16. cv = threading.Condition(lock) # used to let our threads sleep when not needed
  17. timer = None # will be used for timing packet sendtimes
  18. first = 0 # first packet in the window
  19. confirmed = 0 # total confirmed packets for the current file
  20. snum = 0 # current number we want to send (sequence number, that is)
  21. char_limit = 500 # max num of characters in one packet's data field
  22. packets = [] # list to be turned into a list of packets
  23. total_packets = 0 # total number of packets
  24. timed_packet = -1 # packet timer corresponds to currently (-1 is a cardinal value)
  25. waking = False # flag if the receiver is waking the sender thread
  26. pack_size = 512 # packet size in bytes
  27. # try opening the file
  28. try:
  29. msgfile = open(msg, 'r')
  30. except IOError:
  31. sys.stderr.write("Failed to open file. Stop being terrible at life pls")
  32. raise SystemExit
  33. # create packets list
  34. while(True):
  35. string = msgfile.read(char_limit)
  36. if (not string):
  37. break
  38. packets.append(packet.create_packet(total_packets, string))
  39. total_packets += 1
  40. # make winsize not bigger than the file allows
  41. winsize = min(winsize, total_packets)
  42. # create socket
  43. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  44. sock.bind(('localhost', rport))
  45. # start receiver thread
  46. # receiver function
  47. def receiver():
  48. global confirmed
  49. global waking
  50. while(True):
  51. # get a packet, turn into packet type
  52. pack, addr = sock.recvfrom(pack_size)
  53. newpacket = packet.parse_udp_data(pack)
  54. lock.acquire()
  55. # what type is this?
  56. if (newpacket.type == 2): # EOT
  57. acklog.write(str(newpacket.seq_num + "\n"))
  58. lock.release()
  59. return
  60. elif (newpacket.type == 1): # data
  61. lock.release()
  62. sys.stderr.write("Got data from receiver. Exiting")
  63. raise SystemExit
  64. else: # ACK packet
  65. acklog.write(str(newpacket.seq_num) + "\n")
  66. print("snum: ", newpacket.seq_num, "confirmed: ", confirmed)
  67. if (newpacket.seq_num > confirmed): # new ACK
  68. confirmed = seq_num + 1
  69. waking = True
  70. cv.notify_all()
  71. recthread = threading.Thread(target=receiver, args=())
  72. #recthread.dameon = True
  73. recthread.start()
  74. # let's get this bread! I mean send some packets
  75. while (confirmed < total_packets):
  76. lock.acquire()
  77. # while we have room for packets in the window, send some
  78. while(snum < confirmed + winsize and snum < total_packets):
  79. sock.sendto(packets[snum].get_udp_data(), (haddr, dport))
  80. seglog.write(str(snum) + "\n")
  81. snum += 1
  82. # use cv to sleep for 0.2s, or if woken up
  83. cv.wait(tmout) # we get lock back when this returns
  84. # check if we woke from timer or not (status of waking flag)
  85. # this means we were woken by an ACK.
  86. if (waking):
  87. # logic to deal with ACKS deal with in receiver
  88. waking = False
  89. else: # we need to reset window
  90. snum = confirmed + 1 # reset to first unconfirmed packet
  91. waking = False
  92. # ensure we don't overflow due to window reaching the end
  93. winsize = min(winsize, total_packets - confirmed)
  94. lock.release()
  95. # send EOT to receiver before closing
  96. sock.sendto(packet.create_eot(snum).get_udp_data(), (haddr, dport))
  97. recthread.join()
  98. sock.close()
  99. # cleanup for testing
  100. seglog.close()
  101. acklog.close()