Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Problems I found:
- - `c` does not need to be a global variable. Also, it never gets reset to 0 before transfer.
- - Why do you write the file size to a temp file, instead of just sending it to the client directly?
- - recv and send does not guarantee that the data does not get broken up. To guarantee that is your responsibility. I'd suggest you to write a wrapper class that receives repeatedly until you are done.
- - **NEVER** open a file simultaneously for writing and reading. File operations are delicate things. Write everything first, compute a checksum, then close the file and read it again, compare the checksums.
- - Learn to use the debugger. Get an IDE like pycharm, and step through your code, that will give you a better understanding of what exactly happens, and what you need to change.
- - You don't need a response from the client if everything is ok. This is already built into the TCP Protocol, as you are using SOCK_STREAM.
- - Don't `file.close()` files that you opened with `with open() as`.
- - The `break` in the server send data loop was indented wrong
- - Actually, no special case is needed for the server send loop final iteration
- So, a little code for you. This fixes the problem that you cannot rely on the `recv` command to return *exactly* the amount of bytes you want. Also, this can do 'receive until we hit character':
- ``` python
- class BufferedReceiver():
- def __init__(self, sock):
- self.sock = sock
- self.buffer = ""
- self.bufferPos = 0
- def _fetch(self):
- while self.bufferPos >= len(self.buffer):
- self.buffer = self.sock.recv(1024)
- # print(self.buffer)
- self.bufferPos = 0
- def take(self, amount):
- result = bytearray()
- while(len(result) < amount):
- # Fetch new data if necessary
- self._fetch()
- result.append(self.buffer[self.bufferPos])
- self.bufferPos += 1
- return bytes(result)
- def take_until(self, ch):
- result = bytearray()
- while True:
- # Fetch new data if necessary
- self._fetch()
- nextByte = self.buffer[self.bufferPos]
- self.bufferPos += 1
- result.append(nextByte)
- if bytes([nextByte]) == ch:
- break
- return bytes(result)
- ```
- Then, I simplified your server send routine after the `else:`:
- ```python
- string = reqCommand.split(' ', 1) # in case of 'put' and 'get' method
- if len(string) > 1:
- reqFile = string[1]
- if string[0] == 'FileDownload':
- with open(reqFile, 'rb') as file_to_send1:
- # get the entire filesize, which sets the read sector to EOF
- file_size = len(file_to_send1.read())
- # reset the read file sector to the start of the file
- file_to_send1.seek(0)
- # pass the file size over to client in a small info chunk
- print('Filesize:', file_size)
- conn.send((str(file_size)+'\n').encode())
- #send the total file size off the client
- c = 0
- while (c*bufsize) < file_size:
- send_data = file_to_send1.read(bufsize)
- conn.send(send_data)
- c += 1
- print('Send Successful')
- ```
- Finally, here the client `get()`:
- ```python
- def get(commandName):
- socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- socket1.connect((HOST, PORT))
- socket1.send(commandName.encode("utf-8"))
- receiver = BufferedReceiver(socket1)
- string = commandName.split(' ', 1)
- inputFile = string[1]
- # before starting to write new file, get file size
- file_size = int(receiver.take_until(b'\n').decode().strip()) # from file_to_send3
- print ('Filesize:', file_size)
- # set byte buffer size
- bufsize = 4096
- # this only opens the file, the while loop controls when to close
- with open(inputFile, 'wb+') as file_to_write:
- # while written bytes to out is less than file_size
- c = 0
- while True:
- # Compute how much bytes we have left to receive
- bytes_left = file_size - bufsize * c
- # If we are almost done, do the final iteration
- if bytes_left <= bufsize:
- file_to_write.write(receiver.take(bytes_left))
- break
- # Otherwise, just continue receiving
- file_to_write.write(receiver.take(bufsize))
- c += 1
- #TODO open file again, verify.
- # Generate MD5 on server while sending. Then, send MD5 to client.
- # Open finished file in client again and compare MD5s
- print('Download Successful')
- socket1.close()
- return
- ```
- Hopefully this helps :)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement