sender.py 3.9 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. waking = False # flag if the receiver is waking the sender thread
  25. pack_size = 512 # packet size in bytes
  26. # try opening the file
  27. try:
  28. msgfile = open(msg, 'r')
  29. except IOError:
  30. sys.stderr.write("Failed to open file. Stop being terrible at life pls")
  31. raise SystemExit
  32. # create packets list
  33. while(True):
  34. string = msgfile.read(char_limit)
  35. if (not string):
  36. break
  37. packets.append(packet.create_packet(total_packets, string))
  38. total_packets += 1
  39. # make winsize not bigger than the file allows
  40. winsize = min(winsize, total_packets)
  41. # create socket
  42. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  43. sock.bind(('', rport))
  44. # start receiver thread
  45. # receiver function
  46. def receiver():
  47. global confirmed
  48. global waking
  49. while(True):
  50. # get a packet, turn into packet type
  51. pack, addr = sock.recvfrom(pack_size)
  52. newpacket = packet.parse_udp_data(pack)
  53. lock.acquire()
  54. # what type is this?
  55. if (newpacket.type == 2): # EOT
  56. acklog.write(str(newpacket.seq_num) + "\n")
  57. lock.release()
  58. return
  59. elif (newpacket.type == 1): # data
  60. lock.release()
  61. sys.stderr.write("Got data from receiver. Exiting")
  62. raise SystemExit
  63. else: # ACK packet
  64. acklog.write(str(newpacket.seq_num) + "\n")
  65. if (newpacket.seq_num >= confirmed): # new ACK
  66. confirmed = newpacket.seq_num + 1
  67. waking = True
  68. cv.notify_all()
  69. lock.release()
  70. recthread = threading.Thread(target=receiver, args=())
  71. #recthread.dameon = True
  72. recthread.start()
  73. # let's get this bread! I mean send some packets
  74. while (confirmed < total_packets):
  75. lock.acquire()
  76. # while we have room for packets in the window, send some
  77. while(snum < confirmed + winsize and snum < total_packets):
  78. sock.sendto(packets[snum].get_udp_data(), (haddr, dport))
  79. seglog.write(str(snum) + "\n")
  80. snum += 1
  81. # use cv to sleep for 0.2s, or if woken up
  82. cv.wait(tmout) # we get lock back when this returns
  83. # check if we woke from timer or not (status of waking flag)
  84. # this means we were woken by an ACK.
  85. if (waking):
  86. # logic to deal with ACKS deal with in receiver
  87. waking = False
  88. else: # we need to reset window
  89. snum = confirmed + 1 # reset to first unconfirmed packet
  90. waking = False
  91. # ensure we don't overflow due to window reaching the end
  92. winsize = min(winsize, total_packets - confirmed)
  93. lock.release()
  94. # send EOT to receiver before closing
  95. sock.sendto(packet.create_eot(snum).get_udp_data(), (haddr, dport))
  96. recthread.join()
  97. sock.close()
  98. # cleanup for testing
  99. seglog.close()
  100. acklog.close()