diff --git a/.DS_Store b/.DS_Store index bd6c3ecaf6cff3fab05e6a8496e4db20b100ab7b..82e45533608ada25774d4d131672d58dd1f46f48 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/client.py b/client.py index f81a82e7da69c5a690f74c3ba22cb39656aaaff4..5167e07c9482a9c5ab63a9fcd862d788b8664fd6 100644 --- a/client.py +++ b/client.py @@ -1,9 +1,10 @@ import socket import sys -import random import segment import hexa import receiver +from connection import Connection +import pickle ''' Pseudocode @@ -18,6 +19,27 @@ Pseudocode 6. Menutup program ''' +#--- Client compile file +def saveFile(segmentPool, folderpath): + filename = input("\nSaving file...\n\nFile name: ") + if ("." in filename): + filename = filename[0:filename.index(".")+1] + + res = "" + for s in segmentPool: + res += s + + res = hexa.byte(res,'latin-1') + + res = pickle.loads(res) + res.name = filename + + f = open(folderpath + "/" + res.name + ".txt", "wb") + f.write(res.content) + f.close() + +#--- Initialize broadcast socket + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) host = socket.gethostname() @@ -26,20 +48,36 @@ print("Host: "+str(host)) if (len(sys.argv) > 1): port = sys.argv[1] s.bind(('127.0.0.1', int(port))) +else: + print("Port number not specified. Run: 'python client.py <port-number> </path/to/folder>'") + exit() + +if (len(sys.argv) > 2): + folderpath = sys.argv[2] +else: + print("Folder not specified. Run: 'python client.py <port-number> </path/to/folder>'") + exit() + +#--- Send broadcast message = "Hello server" s.sendto(message.encode(),('127.0.0.1',1337)) print("Sent broadcast: "+message) + + +#--- TCP over UDP, receive file from server + fin = False -server_seq_num = None -n_data_sent = 0 -n_data_received = 0 +serverConnection = Connection('127.0.0.1', 1337, 0) stage = "RECEIVE_SYN_SEND_SYN_ACK" received_data = None +segmentPool = [] + while (not(fin)): + # 1. client menerima SYN dari server, lalu mengirim SYN-ACK if (stage == "RECEIVE_SYN_SEND_SYN_ACK"): data, address = s.recvfrom(32777) @@ -49,21 +87,21 @@ while (not(fin)): rec_packet.build(r.receiveSegment(data)) if (r.isSynSegment(rec_packet) and not(r.isAckSegment(rec_packet))): - #if server send SYN to start connection, + #if server send SYN untuk memulai koneksi seq_num0 = rec_packet.getSeqNum() - server_seq_num = seq_num0 + serverConnection.server_seq_num = seq_num0 print("\nSYN received with seq num: "+str(seq_num0)) ack_packet = segment.Segment() - #--- Nanti set seq_num sama ack_num pake go-back-n ---# - n_data_received += 1 + #--- Nanti set seq_num sama ack_num pake go-back-n?? ---# + serverConnection.n_data_received += 1 - seq_num = server_seq_num #paket pertama - ack_num = seq_num0 + n_data_received #ekspektasi: seq_num berikut adalah seq_num + 1 + seq_num = serverConnection.server_seq_num #paket pertama, random sequence number + ack_num = seq_num0 + serverConnection.n_data_received #ekspektasi: seq_num berikut adalah seq_num + 1 - n_data_sent += 1 + serverConnection.n_data_sent += 1 #--- END ---# ack_packet.switchFlag("SYN") @@ -74,9 +112,11 @@ while (not(fin)): message = hexa.byte(ack_packet.construct(),'utf-8') s.sendto(message, (address[0], address[1])) - print("\nSent SYN-ACK with seq_num: "+str(seq_num)+" and ack num: "+str(ack_num)) + print("\nSYN-ACK sent with seq_num: "+str(seq_num)+" and ack num: "+str(ack_num)) stage = "RECEIVE_ACK" + + # 2. client menerima ACK dari server elif (stage == "RECEIVE_ACK"): data, address = s.recvfrom(32777) @@ -86,17 +126,22 @@ while (not(fin)): rec_packet.build(r.receiveSegment(data)) if (not(r.isSynSegment(rec_packet)) and r.isAckSegment(rec_packet)): - #if server send ACK to acknowledge client SYN, + #if server mengirim ACK untuk acknowledge client SYN, seq_num0 = rec_packet.getSeqNum() ack_num0 = rec_packet.getAckNum() print("\nACK received with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) - if (seq_num0 == server_seq_num + n_data_received): + if (seq_num0 == serverConnection.server_seq_num + serverConnection.n_data_received): print("\nConnection established, receiving data...") stage = "RECEIVE_DATA" + + # 3. client menerima data dari server elif (stage == "RECEIVE_DATA"): + + #--- RECEIVE DATA, belum konkuren ---# + data, address = s.recvfrom(32777) r = receiver.Receiver() @@ -105,23 +150,25 @@ while (not(fin)): rec_packet.build(r.receiveSegment(data)) if (r.isDataSegment(rec_packet)): - #if server send data + #if server send data ke client seq_num0 = rec_packet.getSeqNum() ack_num0 = rec_packet.getSeqNum() print("\nData received with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) - if (seq_num0 == server_seq_num + n_data_received): #curr_ack_num masih sama karena sebelum ini, client belum menerima paket dengan payload + if (seq_num0 == serverConnection.server_seq_num + serverConnection.n_data_received): #curr_ack_num masih sama karena sebelum ini, client belum menerima paket dengan payload received_data = rec_packet.getPayLoad() - print("\nReceived data: "+received_data) + print("\nReceived data from server") + + segmentPool.append(received_data) ack_packet = segment.Segment() #--- Nanti set seq_num sama ack_num pake go-back-n ---# - n_data_received += len(received_data) #tambah jumlah bit dalam payload + serverConnection.n_data_received += len(received_data) #tambah jumlah bit dalam payload - seq_num = server_seq_num + n_data_sent - ack_num = server_seq_num + n_data_received + seq_num = serverConnection.server_seq_num + serverConnection.n_data_sent + ack_num = serverConnection.server_seq_num + serverConnection.n_data_received #--- END ---# ack_packet.switchFlag("ACK") @@ -131,16 +178,17 @@ while (not(fin)): message = hexa.byte(ack_packet.construct(),'utf-8') s.sendto(message, (address[0], address[1])) - print("\nSent ACK with seq_num: "+str(seq_num)+" and ack num: "+str(ack_num)) + print("\nACK sent with seq_num: "+str(seq_num)+" and ack num: "+str(ack_num)) - stage = "CLOSE_CONNECTION" - elif (stage == "CLOSE_CONNECTION"): - data, address = s.recvfrom(32777) - - r = receiver.Receiver() - rec_packet = segment.Segment() + elif (r.isFinSegment(rec_packet)): + #if server send FIN - rec_packet.build(r.receiveSegment(data)) + saveFile(segmentPool, folderpath) + + stage = "CLOSE_CONNECTION" + + # 4. server menutup koneksi, client mengikuti + elif (stage == "CLOSE_CONNECTION"): if (r.isFinSegment(rec_packet)): #if server close connection @@ -149,14 +197,14 @@ while (not(fin)): print("\nFIN received with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) - if (seq_num0 == server_seq_num + n_data_received): + if (seq_num0 == serverConnection.server_seq_num + serverConnection.n_data_received): ack_packet = segment.Segment() #--- Nanti set seq_num sama ack_num pake go-back-n ---# - n_data_received += 1 + serverConnection.n_data_received += 1 - seq_num = server_seq_num + n_data_sent - ack_num = server_seq_num + n_data_received + seq_num = serverConnection.server_seq_num + serverConnection.n_data_sent + ack_num = serverConnection.server_seq_num + serverConnection.n_data_received #--- END ---# ack_packet.switchFlag("ACK") @@ -171,10 +219,10 @@ while (not(fin)): fin_packet = segment.Segment() #--- Nanti set seq_num sama ack_num pake go-back-n ---# - seq_num = server_seq_num + n_data_sent - ack_num = server_seq_num + n_data_received + seq_num = serverConnection.server_seq_num + serverConnection.n_data_sent + ack_num = serverConnection.server_seq_num + serverConnection.n_data_received - n_data_sent += 1 + serverConnection.n_data_sent += 1 #--- END ---# fin_packet.switchFlag("FIN") diff --git a/connection.py b/connection.py new file mode 100644 index 0000000000000000000000000000000000000000..51f05bc2fed7b15a6eed70bc97bb6b024d105e0b --- /dev/null +++ b/connection.py @@ -0,0 +1,8 @@ +class Connection: + def __init__(self, IP, port, initial_seq_num): + self.IP = IP + self.port = port + self.name = IP+":"+str(port) + self.initial_seq_num = initial_seq_num + self.n_data_sent = 0 + self.n_data_received = 0 \ No newline at end of file diff --git a/server.py b/server.py index 585852671b00a36abd04e45bb653194cad5fa006..a1f45bf6400dbc07c307212d17fa1ad038af2960 100644 --- a/server.py +++ b/server.py @@ -5,6 +5,7 @@ import hexa import transmitter import receiver import random +from connection import Connection NUMBERS = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"] @@ -30,13 +31,20 @@ Pseudocode: ''' s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + if (len(sys.argv) > 1): port = int(sys.argv[1]) print("Server started at port "+str(port)+"...") +else: + print("Port number not specified. Run: 'python server.py <port-number> </path/to/file>'") + exit() +if (len(sys.argv) > 2): + filepath = sys.argv[2] else: - print("Port number not specified. Run: 'python server.py <port-number>'") + print("File not specified. Run: 'python server.py <port-number> </path/to/file>'") exit() + s.bind(('127.0.0.1',port)) def listen_broadcast(): @@ -47,7 +55,8 @@ def listen_broadcast(): while True: data, address = s.recvfrom(1024) client = str(address[0])+":"+str(address[1]) - clients.append(address) + connectionObj = Connection(address[0], address[1], 0) + clients.append(connectionObj) print("[!] Client ("+client+") found") cont = input("[?] Listen more? (y/n) ").lower() if (cont == "n" or cont != "y"): @@ -60,35 +69,40 @@ def listen_broadcast(): def list_clients(clients): print(NUMBERS[len(clients)].title()+" clients found:") for i in range(len(clients)): - print(str(i+1)+". "+str(clients[i][0])+":"+str(clients[i][1])) + print(str(i+1)+". "+str(clients[i].IP)+":"+str(clients[i].port)) return clients -def send_and_connect(clients): +def send_and_connect(clients, filepath): print("\nCommencing file transfer...") + # server menghubungi setiap client dan mengirim filenya for client in clients: - connect(client) + connect(client, filepath) -def connect(client): - IP = client[0] - port = client[1] + print("\n\nFiles sent. Closing connection...\n") + + # server mengakhiri hubungan dengan setiap client + for client in clients: + closeConnection(client) + +def connect(clientConnection, filepath): + IP = clientConnection.IP + port = clientConnection.port stage = "SEND_SYN" server_seq_num = random.randint(0, 4294967295) - n_data_sent = 0 - n_data_received = 0 + clientConnection.server_seq_num = server_seq_num fin = False while not(fin): + # 1. server kirim SYN ke client untuk memulai koneksi if (stage == "SEND_SYN"): - #send SYN - syn_packet = segment.Segment() seq_num = server_seq_num #kirim random secure integer sebagai seq_num awal server #--- Nanti set seq_num sama ack_num pake go-back-n ---# - n_data_sent += 1 #tambah satu karena mengirim paket SYN (kalo paket ACK saja tidak diinkremen) + clientConnection.n_data_sent += 1 #tambah satu karena mengirim paket SYN (kalo paket ACK saja tidak diinkremen) #--- END ---# syn_packet.switchFlag("SYN") @@ -97,7 +111,11 @@ def connect(client): message = hexa.byte(syn_packet.construct(),'utf-8') s.sendto(message, (IP, port)) + print("\nSYN sent to client "+IP+":"+str(port)+" with seq num: "+str(seq_num)) + stage = "RECEIVE_SYN_ACK_SEND_ACK" + + # 2. server menerima SYN-ACK dari client, lalu mengirim ACK untuk acknowledge SYN tersebut elif (stage == "RECEIVE_SYN_ACK_SEND_ACK"): data, address = s.recvfrom(32777) rec_packet = segment.Segment() @@ -114,11 +132,10 @@ def connect(client): ack_packet = segment.Segment() #--- Nanti set seq_num sama ack_num pake go-back-n ---# - n_data_received += 1 #diinkremen karena menerima paket SYN + clientConnection.n_data_received += 1 #diinkremen karena menerima paket SYN - seq_num = server_seq_num + n_data_sent - ack_num = server_seq_num + n_data_received - curr_ack_num = ack_num + seq_num = server_seq_num + clientConnection.n_data_sent + ack_num = server_seq_num + clientConnection.n_data_received #--- END ---# ack_packet.switchFlag("ACK") @@ -132,115 +149,127 @@ def connect(client): stage = "SEND_FILE" + # 3. server mengirim file elif (stage == "SEND_FILE"): print("\nSending file...") - tm = transmitter.Transmitter(server_seq_num + n_data_received) - tm.prepareSegment("./test.txt") + tm = transmitter.Transmitter(server_seq_num + clientConnection.n_data_received) + tm.prepareSegment(filepath) - message = tm.transmitSegment(0) - s.sendto(message, (IP, port)) + #--- SLIDING WINDOW, belum konkuren ---# + for i in range(len(tm.segmentQueue)): - r = receiver.Receiver() - rec_packet = segment.Segment() + #--- DRAFT TRANSMIT ---# + message = tm.transmitSegment(i) #kirim segmen ke-i + s.sendto(message, (IP, port)) - rec_packet.build(r.receiveSegment(data)) - n_data_sent += len(tm.segmentQueue[0].getPayLoad()) + clientConnection.n_data_sent += len(tm.segmentQueue[i].getPayLoad()) + #--- END ---# - stage = "FIN" - elif (stage == "FIN"): - data, address = s.recvfrom(32777) - rec_packet = segment.Segment() - r = receiver.Receiver() + #--- DRAFT RECEIVE ACK, belum konkuren ---# + data, address = s.recvfrom(32777) + rec_packet = segment.Segment() + r = receiver.Receiver() - rec_packet.build(r.receiveSegment(data)) + rec_packet.build(r.receiveSegment(data)) - if (r.isAckSegment(rec_packet)): - #server receive ACK of file sent - seq_num0 = rec_packet.getSeqNum() - ack_num0 = rec_packet.getAckNum() + if (r.isAckSegment(rec_packet)): + #server receive ACK of file sent + seq_num0 = rec_packet.getSeqNum() + ack_num0 = rec_packet.getAckNum() - print("\nACK received from client "+address[0]+":"+str(address[1])+" with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) + print("\nACK received from client "+address[0]+":"+str(address[1])+" with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) + + #--- SLIDING WINDOW ---# - if ((address[0] == IP) and (address[1] == port)): - print("\nClosing connection with client: "+IP+":"+str(port)) + # 4. urusan sudah selesai, server berhenti mengirim koneksi - #server send FIN to close connection - - fin_packet = segment.Segment() + fin = True - #--- Nanti set seq_num sama ack_num pake go-back-n ---# - seq_num = server_seq_num + n_data_sent - ack_num = server_seq_num + n_data_received - - n_data_sent += 1 - #--- END ---# - fin_packet.switchFlag("FIN") - fin_packet.setSeqNum(seq_num) - fin_packet.setAckNum(ack_num) +def closeConnection(clientConnection): + IP = clientConnection.IP + port = clientConnection.port + server_seq_num = clientConnection.server_seq_num + fin = False - message = hexa.byte(fin_packet.construct(), 'utf-8') - s.sendto(message, (IP, port)) + #--- CLOSING ---# - print("\nFIN sent to client "+IP+":"+str(port)+" with seq num: "+str(seq_num)+" and ack_num: "+str(ack_num)) + print("\nClosing connection with client: "+IP+":"+str(port)) - data, address = s.recvfrom(32777) - rec_packet = segment.Segment() - r = receiver.Receiver() + #server send FIN to close connection - rec_packet.build(r.receiveSegment(data)) + fin_packet = segment.Segment() - if (r.isAckSegment(rec_packet)): - #server receive ACK of server's FIN + seq_num = server_seq_num + clientConnection.n_data_sent + ack_num = server_seq_num + clientConnection.n_data_received + + clientConnection.n_data_sent += 1 - if ((address[0] == IP) and (address[1] == port)): - seq_num0 = rec_packet.getSeqNum() - ack_num0 = rec_packet.getAckNum() + fin_packet.switchFlag("FIN") + fin_packet.setSeqNum(seq_num) + fin_packet.setAckNum(ack_num) - print("\nACK received from client "+address[0]+":"+str(address[1])+" with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) + message = hexa.byte(fin_packet.construct(), 'utf-8') + s.sendto(message, (IP, port)) - data, address = s.recvfrom(32777) - rec_packet = segment.Segment() - r = receiver.Receiver() + print("\nFIN sent to client "+IP+":"+str(port)+" with seq num: "+str(seq_num)+" and ack_num: "+str(ack_num)) + + while (fin != True): + data, address = s.recvfrom(32777) + rec_packet = segment.Segment() + r = receiver.Receiver() + + rec_packet.build(r.receiveSegment(data)) + + if (r.isAckSegment(rec_packet)): + #server receive ACK of server's FIN + if ((address[0] == IP) and (address[1] == port)): + seq_num0 = rec_packet.getSeqNum() + ack_num0 = rec_packet.getAckNum() + + print("\nACK received from client "+address[0]+":"+str(address[1])+" with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) - rec_packet.build(r.receiveSegment(data)) + data, address = s.recvfrom(32777) + rec_packet = segment.Segment() + r = receiver.Receiver() - if (r.isFinSegment(rec_packet)): - #sender receive FIN to close connection - seq_num0 = rec_packet.getSeqNum() - ack_num0 = rec_packet.getAckNum() + rec_packet.build(r.receiveSegment(data)) - print(address) + if (r.isFinSegment(rec_packet)): + #sender receive FIN to close connection + seq_num0 = rec_packet.getSeqNum() + ack_num0 = rec_packet.getAckNum() - if ((address[0] == IP) and (address[1] == port)): - #if correct client wants to close + if ((address[0] == IP) and (address[1] == port)): + #if correct client wants to close - print("\nFIN received from client "+address[0]+":"+str(address[1])+" with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) + print("\nFIN received from client "+address[0]+":"+str(address[1])+" with seq num: "+str(seq_num0)+" and ack num: "+str(ack_num0)) - ack_packet = segment.Segment() + ack_packet = segment.Segment() - #--- Nanti set seq_num sama ack_num pake go-back-n ---# - n_data_received += 1 + #--- Nanti set seq_num sama ack_num pake go-back-n ---# + clientConnection.n_data_received += 1 - seq_num = server_seq_num + n_data_sent - ack_num = server_seq_num + n_data_received - #--- END ---# + seq_num = server_seq_num + clientConnection.n_data_sent + ack_num = server_seq_num + clientConnection.n_data_received + #--- END ---# - ack_packet.switchFlag("ACK") - ack_packet.setSeqNum(seq_num) - ack_packet.setAckNum(ack_num) + ack_packet.switchFlag("ACK") + ack_packet.setSeqNum(seq_num) + ack_packet.setAckNum(ack_num) - message = hexa.byte(ack_packet.construct(), 'utf-8') - s.sendto(message, (IP, port)) + message = hexa.byte(ack_packet.construct(), 'utf-8') + s.sendto(message, (IP, port)) - print("\nACK sent to client "+IP+":"+str(port)+" with seq_num: "+str(seq_num)+" and ack_num: "+str(ack_num)) + print("\nACK sent to client "+IP+":"+str(port)+" with seq_num: "+str(seq_num)+" and ack_num: "+str(ack_num)) - fin = True #close connection + fin = True #close connection - print("\nConnection with client "+IP+":"+str(port)+" closed.") + print("\nConnection with client "+IP+":"+str(port)+" closed.") +#--- Main ---# clients = listen_broadcast() -send_and_connect(clients) +send_and_connect(clients, filepath) diff --git a/test/test1.txt b/test/test1.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c7d9cac163e12d8e87677f93a98a7b5d7abbc07 --- /dev/null +++ b/test/test1.txt @@ -0,0 +1 @@ +hello world byte \ No newline at end of file diff --git a/testtest1.txt b/testtest1.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c7d9cac163e12d8e87677f93a98a7b5d7abbc07 --- /dev/null +++ b/testtest1.txt @@ -0,0 +1 @@ +hello world byte \ No newline at end of file diff --git a/transmitter.py b/transmitter.py index a205c7d972ea8fda4abeb411eb139cda9a23e9b6..a074cde3358275a8c1a4dd56e5234175fe377969 100644 --- a/transmitter.py +++ b/transmitter.py @@ -16,7 +16,7 @@ class Transmitter: - segmentQueue : queue of segments ''' self.segmentQueue = [] - self.counter_start = counter_start + self.counter = counter_start def prepareSegment(self,filePath : str): ''' @@ -27,14 +27,14 @@ class Transmitter: ''' handler = filehandler.FileHandler() fileHexString = handler.dumpFile(filePath) - counter = self.counter_start for i in range(0,len(fileHexString),segment.PAYLOAD_MAX_HEXLENGTH): s = segment.Segment() - s.setSeqNum(counter) + s.setSeqNum(self.counter) s.loadPayLoad(fileHexString[i:i + segment.PAYLOAD_MAX_HEXLENGTH]) s.switchFlag("DATA") self.segmentQueue.append(s) - counter += 1 + self.counter += len(s.getPayLoad()) + print(self.counter) def transmitSegment(self,index : int) -> bytes: '''