Home Ask Login Register

Developers Planet

Your answer is one click away!

Fahad Cheema February 2016

Need to transfer multiple files from client to server

I'm recently working on a project in which I'm basically making a dropbox clone. The server and client are working fine but I'm having a slight issue. I'm able to transfer a single file from the client to the server but when I try to transfer all the files together it gives me an error after the transfer of the first file so basically my code is only working for a single file. I need to make it work for multiple files. Any help will be appreciated. Here's my code

Server Code

import socket
import thread
import hashlib

serversock = socket.socket()
host = socket.gethostname();
port = 9000;
serversock.bind((host,port));
filename = ""
serversock.listen(10);
print "Waiting for a connection....."

clientsocket,addr = serversock.accept() 
print("Got a connection from %s" % str(addr))
while True:
    size = clientsocket.recv(1)
    filesz = clientsocket.recv(1)
    if filesz.isdigit():
        size += filesz
        filesize = int(size)
    else:
        filesize = int(size)    
    print filesize
    for i in range(0,filesize):
        if filesz.isdigit():
            filename += clientsocket.recv(1)
        else:
            filename += filesz
            filesz = "0"
    print filename      
    file_to_write = open(filename, 'wb')
    while True:
        data = clientsocket.recv(1024)
        #print data
        if not data:
            break
        file_to_write.write(data)
    file_to_write.close()
    print 'File received successfully'
serversock.close()

Client Code

import socket
import os
import thread

s = socket.socket() 
host = socket.gethostname()                           
port = 9000
s.connect((host, port))
path = "C:\Users\Fahad\Desktop"
directory = os.listdir(path)
for files in directory:
    print files  
    filename = files
    size = bytes(len(filename))
    #print size
    s.send(size)
    s.send(filename)
    file_to_send = open(filename, 'rb')
    l = file_        

Answers


Padraic Cunningham February 2016

You could create multiple sockets and write using makefile:

server:

import socket
import threading
import time

serversock = socket.socket()
host = socket.gethostname()
port = 9000
serversock.bind((host, port))

serversock.listen(10)
print("Waiting for a connection.....")


def reader(client):
    fle = client.makefile('r')
    filename = fle.readline()
    client.send("Got file {}\n".format(filename))
    file_to_write = open(filename.rstrip(), 'wb')
    client.send("Starting writing {}\n".format(filename))
    file_to_write.write(fle.read())
    file_to_write.close()
    client.send("Finished writing {}\n".format(filename))


while True:
    client, addr = serversock.accept()
    print("Got a connection from %s" % str(addr))
    client_serve_thread = threading.Thread(target=reader, args=tuple((client,)))
    client_serve_thread.start()
    time.sleep(0.001)

serversock.close()

client:

import socket
import os
import thread
import os

host = socket.gethostname()
port = 9000

path = "/home/padraic/t"
directory = os.listdir(path)
for file in directory:
    s = socket.socket()
    s.connect((host, port))
    filename = os.path.join(path, file)
    s.send(file+"\n")
    print(s.recv(1024))
    file_to_send = open(os.path.join(path, file), 'rb')
    s.send(file_to_send.read())
    print('File Sent\n')
    file_to_send.close()
    rec = s.recv(1024)
    print(rec)
    s.close()


Gil Hamilton February 2016

I believe you're actually receiving all the files' content but then writing them all to one file.

Your server is only accepting a single connection and it writes whatever data it receives into the file until it receives no more data. That won't happen until the client closes its socket at the end.

There are a couple of ways to fix this.

  1. Move the accept call into the server loop and the connect call into the client loop. Have your client connect, send the filename, transfer the entire content of a single file, then close the connection. On the next iteration, do it all over again.
  2. Alternatively, at the beginning of each file, have the client send to the server both the filename to be transferred and the file size (so the server knows how to find the end of the file content). Then write exactly that many bytes to the server. (But see also below as to transmitting the file size.)

I would recommend (1) as more robust and easier to implement.

Second subject: your mechanism for sending the filename is flawed. If I follow it correctly, your program would not work properly if the filename being transmitted begins with a digit as the server will not be able to determine how many bytes are being used to send the filename length. There are two usual ways of sending numbers:

  1. Use the struct module to format a binary integer in a well-defined way. You actually send the "packed" format, and the server would unpack it. It would then know exactly how many bytes long to receive for the filename.
  2. Just send a header line containing the filename followed by a null byte or newline (or some other well-defined defined terminator byte). Then the server can read a byte at a time of the filename until it sees the terminator.


Jesper Freesbug February 2016

There are several minor issues in your snippet. Maybe you could do something like this?

import socket
import thread
import hashlib

serversock = socket.socket()
host = socket.gethostname();
port = 9000;
serversock.bind((host,port));
filename = ""
serversock.listen(10);
print "Waiting for a connection....."

clientsocket,addr = serversock.accept()
print("Got a connection from %s" % str(addr))
while True:
    size = clientsocket.recv(16) # Note that you limit your filename length to 255 bytes.
    if not size:
        break
    size = int(size, 2)
    filename = clientsocket.recv(size)
    filesize = clientsocket.recv(32)
    filesize = int(filesize, 2)
    file_to_write = open(filename, 'wb')
    chunksize = 4096
    while filesize > 0:
        if filesize < chunksize:
            chunksize = filesize
        data = clientsocket.recv(chunksize)
        file_to_write.write(data)
        filesize -= chunksize

    file_to_write.close()
    print 'File received successfully'
serversock.close()

Client: import socket import os import thread

s = socket.socket()
host = socket.gethostname()
port = 9000
s.connect((host, port))
path = "blah"
directory = os.listdir(path)
for files in directory:
    print files
    filename = files
    size = len(filename)
    size = bin(size)[2:].zfill(16) # encode filename size as 16 bit binary
    s.send(size)
    s.send(filename)

    filename = os.path.join(path,filename)
    filesize = os.path.getsize(filename)
    filesize = bin(filesize)[2:].zfill(32) # encode filesize as 32 bit binary
    s.send(filesize)

    file_to_send = open(filename, 'rb')

    l = file_to_send.read()
    s.sendall(l)
    file_to_send.close()
    print 'File Sent'

s.close()

Here the client also sends the size of the file. Both size and filesize are encoded as binary strings (you could do another method). The filename length (size) can take values up to 2^16 and the send file

Post Status

Asked in February 2016
Viewed 1,067 times
Voted 9
Answered 3 times

Search




Leave an answer


Quote of the day: live life