需要将多个文件从客户端传输到服务器

Need to transfer multiple files from client to server

我最近在做一个项目,基本上是在制作一个保管箱克隆。服务器和客户端工作正常,但我遇到了一个小问题。我能够将单个文件从客户端传输到服务器,但是当我尝试将所有文​​件一起传输时,它在传输第一个文件后给我一个错误,所以基本上我的代码只适用于单个文件。我需要让它适用于多个文件。任何帮助将不胜感激。这是我的代码

服务器代码

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: ''

您可以创建多个套接字并使用 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()

我相信您实际上是在接收所有文件的内容,然后将它们全部写入一个文件。

您的服务器只接受一个连接,它会将接收到的任何数据写入文件,直到不再接收到数据为止。在客户端最后关闭其套接字之前,这种情况不会发生。

有几种方法可以解决这个问题。

  1. accept 调用移至服务器循环,将 connect 调用移至客户端循环。让您的客户端连接、发送文件名、传输单个文件的全部内容,然后关闭 连接。在下一次迭代中,重新做一遍。
  2. 或者,在每个文件的开头,让客户端向服务器发送要传输的文件名和文件大小(以便服务器知道如何找到文件内容的结尾)。然后向服务器写入那么多字节。 (但另见下文关于传输文件大小的信息。)

我会推荐 (1),因为它更健壮且更易于实施。

第二个主题:您发送文件名的机制存在缺陷。如果我遵循正确,如果传输的文件名以数字开头,您的程序将无法正常工作,因为服务器将无法确定用于发送文件名长度的字节数。常用的发号方式有两种:

  1. 使用struct模块以well-defined方式格式化二进制整数。你实际上发送了 "packed" 格式,服务器会解压它。然后它会确切知道要为文件名接收多少字节。
  2. 只需发送包含文件名的 header 行,后跟一个空字节或换行符(或其他一些 well-defined 定义的终止符字节)。然后服务器可以一次读取文件名的一个字节,直到它看到终止符。

您的代码段中存在几个小问题。也许你可以做这样的事情?

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)。