sender.py 4.06 KB
Newer Older
wx002's avatar
wx002 committed
1 2
import socket
import base64
wx002's avatar
wx002 committed
3 4 5
import re
import linecache
import sys
wx002's avatar
wx002 committed
6
import argparse
wx002's avatar
wx002 committed
7

wx002's avatar
wx002 committed
8
def PrintException():
wx002's avatar
wx002 committed
9 10 11 12 13
    '''
       Print detail exception details
       taken from: https://stackoverflow.com/questions/14519177/python-exception-handling-line-number
       :return:
       '''
wx002's avatar
wx002 committed
14 15 16 17 18 19 20
    exc_type, exc_obj, tb = sys.exc_info()
    f = tb.tb_frame
    lineno = tb.tb_lineno
    filename = f.f_code.co_filename
    linecache.checkcache(filename)
    line = linecache.getline(filename, lineno, f.f_globals)
    print ('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj))
wx002's avatar
wx002 committed
21 22 23 24

def chunk(line, size=1028):
    return [line[i:i+size] for i in range(0,len(line), size)]

wx002's avatar
wx002 committed
25

wx002's avatar
wx002 committed
26 27 28
def hash_string(string):
    str_hash =  base64.b64encode(string.encode()) + b'\t'
    return str_hash
wx002's avatar
wx002 committed
29

wx002's avatar
wx002 committed
30 31 32 33 34

def send_line(network, dest, line_bytes, size):
    if len(line_bytes) < size:
        # send the line directly if is less than the max size
        network.sendto(line_bytes, dest)
wx002's avatar
wx002 committed
35
    else:
wx002's avatar
wx002 committed
36
        lineChunks = chunk(line_bytes, size)
wx002's avatar
wx002 committed
37
        for c in lineChunks:
wx002's avatar
wx002 committed
38 39 40 41 42 43 44 45 46 47
            network.sendto(c, dest)

    network.sendto(b'####', dest)

def build_packet(index, line):
    hash_index = hash_string(str(index))
    hash_str = hash_string(line)
    hashed_line = hash_index + hash_str + line.encode()
    return hashed_line

wx002's avatar
wx002 committed
48

wx002's avatar
wx002 committed
49 50 51
def rdt_sendFile(network, dest, filename, size=65536):
    # generate lines from file
    file = open(filename)
Alan Marchiori's avatar
Alan Marchiori committed
52
    lines = file.readlines()  #will this work with binary files?
wx002's avatar
wx002 committed
53 54 55
    line_count = len(lines)
    currentIndex = 0
    while currentIndex < line_count:
wx002's avatar
wx002 committed
56 57 58 59
        ack = False
        while not ack:
            try:
                # build hash
wx002's avatar
wx002 committed
60 61 62

                hashed_line = build_packet(currentIndex, lines[currentIndex])
                #print('index: {}\tLine:{}'.format(currentIndex,lines[currentIndex]))
wx002's avatar
wx002 committed
63
                send_line(network, dest, hashed_line, size)
wx002's avatar
wx002 committed
64
                print('sending packet index {}'.format(currentIndex))
wx002's avatar
wx002 committed
65
                data = network.recv(size)
wx002's avatar
wx002 committed
66 67 68 69 70 71

                #handle acks
                ackList = re.split('\t', data.decode(), maxsplit=1)
                index = int(base64.b64decode(ackList[1].encode()))
                print('Got ack for packet {} and currentIndex is {}'.format(index, currentIndex))
                if ackList[0] == 'ACK' and index == currentIndex:
wx002's avatar
wx002 committed
72
                    ack = True
wx002's avatar
wx002 committed
73 74 75 76 77
                    currentIndex += 1
                    print("acked! packet index is now {}".format(currentIndex))
                elif data == b'NNNN':
                    #current_line = build_packet(currentIndex, lines[currentIndex])
                    print('resending packet {},{}'.format(currentIndex, lines[currentIndex]))
wx002's avatar
wx002 committed
78
                    send_line(network, dest, hashed_line, size)
Alan Marchiori's avatar
Alan Marchiori committed
79 80 81
            except KeyboardInterrupt:
                print('Ctrl-c, goodbye!')
                exit()
wx002's avatar
wx002 committed
82
            except socket.timeout:
wx002's avatar
wx002 committed
83 84 85 86 87 88 89 90 91 92 93 94
                print('timeout!')
            except:
                PrintException()

    END = False
    while not END:
        network.sendto(b'END', dest)
        data = network.recv(size)
        if data == b'END':
            END = True
    network.close()

wx002's avatar
wx002 committed
95

wx002's avatar
wx002 committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
def get_argus():
    '''
    gets the arguements
    :return:
    '''
    parser = argparse.ArgumentParser(
        description="Sender For RDT stop and wait with checksum"
    )
    parser.add_argument('--remote_addr',
                        default='127.0.0.1',
                        help='The remote address to send to.')
    parser.add_argument('--remote_port',
                        default=8880, type=int,
                        help='The remote address port')
    parser.add_argument('--file',
                        default='sendData/alice.txt',
                        help='The file to send')
    return parser.parse_args()

wx002's avatar
wx002 committed
115 116

if __name__ == '__main__':
wx002's avatar
wx002 committed
117 118 119
    argus = get_argus()
    ip = argus.remote_addr
    port = argus.remote_port
wx002's avatar
wx002 committed
120
    dest = (ip, port)
wx002's avatar
wx002 committed
121
    timeOut = 10
wx002's avatar
wx002 committed
122 123
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(timeOut)
wx002's avatar
wx002 committed
124 125 126
    file_name = 'alice.txt'
    filepath = 'sendData/'+file_name
    rdt_sendFile(sock, dest, filepath)