Search code examples
pythonfile-transfertcpsocket

Python multiple file transfer over TCP sockets


I am trying to write a program in python to transfer multiple files in a folder over a socket, I have the following code so far

Client:

def uploadFiles(folder,dcip,PORT,filetype):
    os.chdir(folder)
    dirList = os.listdir(folder)
    print dirList
    ms = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print PORT
    ms.connect((dcip, int(PORT)))
    for fname in dirList:

        if fname.endswith(str(filetype)):
            cmd = 'get\n%s\n' % (fname)
            ms.sendall(cmd)
            f = open(fname,'rb')
            data = f.read()
            f.close()
            print data
            r = ms.recv(2)
            ms.sendall(data)
            ms.sendall('done\n%s\n' %(fname))
    ms.sendall('end\n\n')   
    ms.close()

Server:

import socket,os
listener_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener_socket.bind(('',33234))
filename = ''
while 1:
    listener_socket.listen(100)
    connection,address_client = listener_socket.accept()
    if not os.path.exists(str(address_client[0])):
        os.makedirs(str(address_client[0]))
    currdir = os.getcwd()
    os.chdir('./'+str(address_client[0]))

    while(1):
        data = connection.recv(4096)
        cmd = data[:data.find('\n')]

        if cmd == 'get':
            x,filename,x = data.split('\n',2)
            connection.sendall('ok')
            f = open(filename,'wb')


        if cmd == 'done':
            continue

        f.write(data)

        if cmd == 'end':
            connection.close()
            break
    os.chdir(currdir)

The above code goes into an infinite loop, which I do understand that it is because of the continue statement in the if cmd == 'done' part, I wonder why it is doing that? I mean it never gets the done message from the client, can anyone please help me fix the code?


Solution

  • Because commands and filenames are in separate lines, it is best to parse received data by lines. Last part of block data doesn't have to finish with a \n, so it has to be merged with next received data block.

    This is (not tested) implementation of parsing received data by lines:

    data = '' # contains last line of a read block if it didn't finish with \n
    in_get, in_done, reading_file, ended = False, False, False, False
    while not ended:
      if len(data) > 100:  # < update
        f.write( data )    # <
        data = ''          # <
      data += connection.recv(4096)
      i = data.find('\n')
      while i >= 0 and not ended:
        line = data[:i]
        data = data[i+1:]
        if in_get:
          filename = line
          reading_file = True
          f = open(filename,'wb')
          in_get = False
        elif in_done:
          if line != filename:  # done inside file content
            f.write( 'done\n' + line + '\n' )
          else:
            f.close()
            reading_file = False
          in_done = False
        else:
          if line == 'get' and not reading_file:
            in_get = True
          elif line == 'done':
            in_done = True
          elif line == 'end' and not reading_file:
            ended = True
            break;
          else:
            f.write( line + '\n' )
        i = data.find('\n')