File transmission over TCP with Python

爱⌒轻易说出口 提交于 2020-08-07 06:41:19

问题


I'm currently working on a python project, that requires file transmission from a client to a server via the Python socket. Here is my current code, that however doesn't transmit the whole file, but there are always some bites missing, or additional bytes, according to the file sizes.

_con and con are connection wrappers connections via the python socket.

Client:

def _sendFile(self, path):
    sendfile = open(path, 'rb')
    data = sendfile.read()

    self._con.sendall(data)

    self._con.send(bytes('FIN', 'utf8'))
    # Get Acknowledgement
    self._con.recv(6)

def _recieveFile(self, path):
    # Recieve the file from the client
    writefile = open(path, 'wb')
    i = 0
    while (1):
        rec = self.con.recv(1024)
        if (rec.endswith(b'FIN')):
            break
        writefile.write(rec)

    self.con.send(b'ACK')

回答1:


While the first problem you have is with not writing the last chunk of data received to the output file, you have a few other problems.

Your current problem can be fixed by changing the if statement to something like the following:

if (rec.endswith(b'FIN')):
    writefile.write(rec[:-3]) # Ignore the last 3 bytes
    break

You still have other problems:

  1. If the file contains the characters FIN, there is a chance of about 1 in 1024 that the characters will be the last 3 in the read buffer, and your code will mistakenly read that as the end marker, and terminate prematurely.

  2. There is also a chance of 2 in 1024 that the FIN marker will be split over two calls to read(), with rec ending with either F or FI.

Both of these problems are caused by TCP being a stream based protocol, with no concept of packets at the user level.

One obvious fix for this is to precede the transmission of the file with a fixed size length indication, with the receiver reading this, and then reading the correct number of bytes.

Something like this:

def _sendFile(self, path):
    sendfile = open(path, 'rb')
    data = sendfile.read()

    self._con.sendall(encode_length(len(data)) # Send the length as a fixed size message
    self._con.sendall(data)


    # Get Acknowledgement
    self._con.recv(1) # Just 1 byte


def _recieveFile(self, path):
    LENGTH_SIZE = 4 # length is a 4 byte int.
    # Recieve the file from the client
    writefile = open(path, 'wb')
    length = decode_length(self.con.read(LENGTH_SIZE) # Read a fixed length integer, 2 or 4 bytes
    while (length):
        rec = self.con.recv(min(1024, length))
        writefile.write(rec)
        length -= sizeof(rec)

    self.con.send(b'A') # single character A to prevent issues with buffering

Of course, when sending / receiving the length, you need to be aware of the ordering of bytes within the length field.




回答2:


In this receive function loop above, you check if the received data ends with FIN, if it does. You just break out of the loop without writing it to the file. So you will be missing the last piece.

while (1):
    rec = self.con.recv(1024)
    if (rec.endswith(b'FIN')):
        break
    writefile.write(rec)


来源:https://stackoverflow.com/questions/5020658/file-transmission-over-tcp-with-python

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!