需要将多个文件从客户端传输到服务器
Posted
技术标签:
【中文标题】需要将多个文件从客户端传输到服务器【英文标题】:Need to transfer multiple files from client to server 【发布时间】:2016-05-16 17:01:20 【问题描述】:我最近在做一个项目,我基本上是在做一个 Dropbox 克隆。服务器和客户端工作正常,但我有一个小问题。我能够将单个文件从客户端传输到服务器,但是当我尝试将所有文件一起传输时,它在传输第一个文件后给我一个错误,所以基本上我的代码只适用于单个文件。我需要让它适用于多个文件。任何帮助将不胜感激。这是我的代码
服务器代码
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()
客户端代码
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()
这是我得到的错误
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】:您的 sn-p 中有几个小问题。也许你可以做这样的事情?
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()
客户:
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()
这里客户端也发送文件的大小。大小和文件大小都被编码为二进制字符串(你可以做另一种方法)。文件名长度(大小)最多可以取 2^16 的值,发送文件最多可以有 2^32 字节(即 2^filesize)。
【讨论】:
如果文件大小大于 2^16 字节怎么办?它不适用于那个文件? 这是服务器所说的:C:\Users\Fahad\Desktop>python server.py 等待连接.....从 ('192.168.0.100', 49349) 获得连接Traceback(最近一次调用最后一次):文件“server.py”,第 22 行,在您可以创建多个套接字并使用 makefile 进行写入:
服务器:
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()
客户:
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()
【讨论】:
我试过了,但它甚至没有连接到服务器:/ 这是客户端所说的: Traceback(最近一次调用最后一次):文件“client.py”,第 12 行,在我相信您实际上收到了所有文件的内容,然后将它们全部写入一个文件。
您的服务器只接受一个连接,它将接收到的任何数据写入文件,直到不再接收到数据。在客户端最终关闭其套接字之前,不会发生这种情况。
有几种方法可以解决此问题。
-
将
accept
调用移至服务器循环,将connect
调用移至客户端循环。让您的客户端连接,发送文件名,传输单个文件的全部内容,然后关闭连接。在下一次迭代中,重新做一遍。
或者,在每个文件的开头,让客户端向服务器发送要传输的文件名和文件大小(这样服务器就知道如何找到文件内容的结尾)。然后将那么多字节写入服务器。 (但关于传输文件大小,另请参见下文。)
我建议 (1) 更健壮且更易于实施。
第二个主题:您发送文件名的机制有缺陷。如果我正确地遵循它,如果正在传输的文件名以数字开头,您的程序将无法正常工作,因为服务器将无法确定用于发送文件名长度的字节数。通常有两种发送号码的方式:
-
使用
struct
模块以明确定义的方式格式化二进制整数。您实际上发送了“打包”格式,服务器将对其进行解包。然后它会确切知道要接收多少字节的文件名。
只需发送一个包含文件名的标题行,后跟一个空字节或换行符(或其他一些明确定义的终止符字节)。然后服务器可以一次读取文件名的一个字节,直到它看到终止符。
【讨论】:
以上是关于需要将多个文件从客户端传输到服务器的主要内容,如果未能解决你的问题,请参考以下文章