问题
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_to_send.read()
s.sendall(l)
file_to_send.close()
print 'File Sent'
s.close()
Here's the error that I get
Waiting for a connection.....
Got a connection from ('192.168.0.100', 58339)
13
Betternet.lnk
File received successfully
Traceback (most recent call last):
File "server.py", line 22, in <module>
filesize = int(size)
ValueError: invalid literal for int() with base 10: ''
回答1:
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 -= len(data)
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 can have up to 2^32 byte (that is 2^filesize).
回答2:
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.
- Move the
accept
call into the server loop and theconnect
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. - 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:
- 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. - 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.
回答3:
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()
来源:https://stackoverflow.com/questions/35245818/need-to-transfer-multiple-files-from-client-to-server