Created
April 2, 2012 02:39
-
-
Save lukesteensen/2280160 to your computer and use it in GitHub Desktop.
Reliable UDP
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
import socket | |
import struct | |
import sys | |
if (len(sys.argv) < 3): | |
print "arguments needed: <port> <filename>" | |
exit() | |
UDP_IP = '' | |
UDP_PORT = int(sys.argv[1]) | |
FILE = sys.argv[2] | |
sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) | |
sock.bind( (UDP_IP, UDP_PORT) ) | |
packets = {} | |
while True: | |
data, addr = sock.recvfrom( 2048 ) # buffer size is 2048 bytes | |
syn, total, msg = struct.unpack('!II1400s', data) | |
sock.sendto( struct.pack('4sI', 'ack:', syn), (addr[0], UDP_PORT + 1) ) | |
print "received packet " + str(syn) + " of " + str(total) | |
print "sent ack for packet " + str(syn) | |
packets[syn] = msg | |
if len(packets) == total: | |
print "got all packets" | |
break | |
print "writing to file" | |
f = open(FILE, "wb") | |
try: | |
for syn, data in sorted(packets.iteritems()): | |
f.write(data) | |
except: | |
print "Error writing file" | |
finally: | |
f.close() | |
print "done." |
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
import threading | |
import socket | |
import struct | |
import sys | |
from time import sleep, time | |
if (len(sys.argv) < 4): | |
print "arguments needed: <hostname> <port> <filename>" | |
exit() | |
UDP_IP = socket.gethostbyname(sys.argv[1]) | |
UDP_PORT = int(sys.argv[2]) | |
FILE = sys.argv[3] | |
print "UDP target IP:", UDP_IP | |
print "UDP target port:", UDP_PORT | |
PACKET_SIZE = 1400 | |
packets = {} | |
f = open(FILE, "rb") | |
try: | |
bytes = f.read(PACKET_SIZE) | |
i = 0 | |
while bytes != "": | |
packets[i] = bytes | |
bytes = f.read(PACKET_SIZE) | |
i = i + 1 | |
except: | |
print "Error reading file" | |
finally: | |
f.close() | |
print "preparing to send " + str(len(packets)) + " packets..." | |
sock = socket.socket( socket.AF_INET, # Internet | |
socket.SOCK_DGRAM ) # UDP | |
acked_packets = set() | |
class AckListener(threading.Thread): | |
def __init__(self, ip, port): | |
threading.Thread.__init__(self) | |
self.sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) | |
self.ip = ip | |
self.port = port | |
def run(self): | |
sock.bind( (self.ip, self.port) ) | |
print 'listening for acks...' | |
while len(acked_packets) < len(packets): | |
data, addr = sock.recvfrom(1024) | |
msg, syn = struct.unpack('4sI', data) | |
if msg == 'ack:': | |
acked_packets.add(syn) | |
print "got ack for packet " + str(syn) | |
listener = AckListener('', UDP_PORT + 1) | |
listener.start() | |
start = time() | |
sent_packets = set() | |
while len(acked_packets) < len(packets): | |
# until all the packets have been acked, keep sending all the packets that haven't been acked | |
for syn, data in packets.iteritems(): | |
if syn not in acked_packets: | |
packed = struct.pack('!II1400s', syn, len(packets), data) | |
print "sending packet " + str(syn) | |
sock.sendto( packed, (UDP_IP, UDP_PORT) ) | |
sent_packets.add(syn) | |
timeout = 0 | |
while len(sent_packets) - len(acked_packets) > 60: | |
timeout += 1 | |
sleep(0.001) | |
if timeout >= 5000: | |
break | |
listener.join() | |
end = time() | |
elapsed = end - start | |
print "done in " + str(elapsed) + " seconds" | |
print "throughput is " + str(10485760 / elapsed) + " bytes / second" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment