【问题标题】:Python Client/Server send big size filesPython客户端/服务器发送大文件
【发布时间】:2013-08-25 16:38:15
【问题描述】:

我不确定这个话题是否已经得到回答,如果是,我很抱歉:

我有一个简单的 python 脚本,将所有文件发送到一个文件夹中:

客户:

import os,sys, socket, time
def Send(sok,data,end="292929"):
    sok.sendall(data + end);
def SendFolder(sok,folder):
    if(os.path.isdir(folder)):
        files = os.listdir(folder);
        os.chdir(folder);
        for file_ in files:
            Send(sok,file_);#Send the file name to the server
            f = open(file_, "rb");
            while(True):
                d = f.read();#read file
                if(d == ""):
                    break;
                Send(sok, d, "");#Send file data
            f.close();
            time.sleep(0.8);#Problem here!!!!!!!!!!!
            Send(sok,"");#Send termination to the server
            time.sleep(1);#Wait the server to write the file
        os.chdir("..");
        Send(sok,"endfile");#let the server know that we finish sending files
    else:
        Send("endfile")#If not folder send termination
try:
    sok1 = socket.socket();
    sok1.connect(("192.168.1.121",4444))#local ip
    time.sleep(1);
    while(True):
        Send(sok1,"Enter folder name to download: ");
        r = sok1.recv(1024);
        SendFolder(sok1,r);
        time.sleep(0.5);
except BaseException, e:
    print "Error: " + str(e);
    os._exit(1);

服务器:

import sys,os,socket,time
# receive data
def Receive(sock, end="292929"):
    data = "";
    while(True):
        if(data.endswith(end)):
            break;
        else:
            data = sock.recv(1024);
    return data[:-len(end)];#return data less termination
def FolderReceive(sok):
    while(True):
        r = Receive(sok);# recv filename or folder termination("endfile")
        if(r == "endfolder"):
            print "Folder receive complete.";
            break;
        else:
            filename = r;#file name
            filedata = Receive(sok);# receive file data
            f = open(filename,"wb");
            f.write(filedata);
            f.close();#finish to write the file
            print "Received: " + filename;
try:
    sok1 = socket.socket();
    sok1.bind(("0.0.0.0",4444));
    sok1.listen(5);
    cl , addr = sok1.accept();#accepts connection
    while(True):
        r = Receive(cl);
        sys.stdout.write("\n" + r);
        next = raw_input();
        cl.sendall(next);#send folder name to the client
        FolderReceive(cl);
except BaseException, e:
    print "Error: " + str(e);
    os._exit(1);

我知道这不是最好的服务器...但我知道。这仅适用于包含小文件的文件夹,因为如果我发送大文件(如 5mb ...),它会崩溃,因为客户端等待服务器的时间不够。

所以我的问题是如何在客户端无需等待的情况下将文件发送到服务器?或者确切地知道客户端需要等待服务器接收文件多少时间?一些执行相同但处理任何文件大小的代码,有什么帮助吗?

【问题讨论】:

  • 是的,我知道 python 不需要“;”和 IF 上的“()”,但我喜欢这样做!!!!
  • 好吧,对于经验丰富的 Python 开发人员来说,这会让你的代码更难阅读——正是你想在这里帮助你的人。
  • 同时,if(data.endswith(end)): 不起作用,因为结束标记可能出现在数据包中的任何地方,而不仅仅是数据包的末尾。 (如果“292929”字符串可以出现在您要发送的文件中,这也是一个大问题——例如,如果您尝试发送包含此脚本的目录……)
  • 另外,拨打sleep 等待其他地方发生的事情绝不是一个好主意。无论你选择什么时间,它总是不够的(当然,在大多数情况下,它会太长,无缘无故减慢你的代码速度)。
  • 好吧,我可以把一些更难的,但我相信这不是为什么不工作......

标签: python file sockets send directory


【解决方案1】:

TCP sockets are byte streams, not message streams。如果要发送一系列单独的消息(例如单独的文件),则需要定义协议,然后编写协议处理程序。没有办法解决这个问题。仅仅猜测时间或试图利用数据包边界是不可能的。

上面链接的博客文章显示了一种方法。但是如果你愿意,你可以用字符串分隔符来做到这一点。但是你必须处理两个问题:

  • 分隔符可以出现在read 数据包中的任何位置,而不仅仅是在末尾。
  • 分隔符可以在数据包边界上拆分 - 您可能会在一次读取结束时获得 "2929",而在下一次读取开始时获得另一个 "29"

通常的做法是累积一个缓冲区,然后在缓冲区的任何位置搜索分隔符。像这样的:

def message(sock, delimiter):
    buf = ''
    while True:
        data = sock.read(4096)
        if not data:
            # If the socket closes with no delimiter, this will
            # treat the last "partial file" as a complete file.
            # If that's not what you want, just return, or raise.
            yield buf
            return
        buf += data
        messages = buf.split(delimiter)
        for message in messages[:-1]:
            yield message
        buf = message[-1]

与此同时,您的分隔符还有另一个问题:没有什么可以阻止它出现在您尝试传输的文件中。例如,如果您尝试发送脚本或此网页会怎样?

这是其他协议通常比分隔符更好的原因之一,但这并不难处理:只需转义文件中的任何分隔符即可。由于您要一次发送整个文件,因此您可以在 sendall 之前使用 replace,在 split 之前使用相反的 replace

【讨论】:

  • 谢谢,我想我会在所有代码中看起来更好,看看什么是让它工作的最佳方法!而且我知道上面的代码简直是一团糟!...
猜你喜欢
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
  • 2017-07-10
  • 2018-06-18
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
相关资源
最近更新 更多