1

我是套接字编程和python的初学者。我想学习如何从服务器向客户端发送一个大文本文件(例如,> 5MB)。我不断收到一条错误消息

Traceback (most recent call last):
  File "fserver.py", line 50, in <module>
    reply = f.read()
ValueError: Mixing iteration and read methods would lose data

以下是我的部分代码。有人可以看一下并给我一些有关如何解决此问题的提示吗?感谢您的时间。

我的服务器.py

#validate filename
        if os.path.exists(filename):
            with open(filename) as f:
                for line in f:
                    reply = f.read()
                    client.send(reply)
            #f = open(filename, 'r')
            #reply = f.read()
            #client.send(piece)
        else:
            reply = 'File not found'
            client.send(reply)

我的客户端.py

while True:
    print 'Enter a command: list or get <filename>'
    command = raw_input()
    if command.strip() == 'quit':
        break
    client_socket.send(command)

    data = client_socket.recv(socksize)
    print data
4

2 回答 2

4

这里的问题与套接字或文件的大小无关。当你这样做时:

for line in f:
    reply = f.read()

尝试一次读取文件的for line in f一行,然后对于每一行,您都尝试读取整个文件。那是行不通的。

如果你没有得到这个错误(在很多情况下你不会),第一次通过循环你会读取并忽略第一行,然后读取并发送除第一行之外的所有内容(或者,可能是所有内容但是第一个,比如说,4KB)作为一个巨大的回复,然后循环就完成了。

你想要的是一个或另一个:

for line in f:
    reply = line

……或者……</p>

# no for loop
reply = f.read()

同时,在您的客户端,您只做一个recv. 这将获得第一个 4K(或其他socksize)或更少,然后您将永远不会收到任何其他内容。

你需要的是一个循环。像这样:

while True:
    data = client_socket.recv(socksize)
    print data

但是现在你有一个新问题。一旦文件完成,客户端将永远坐在那里等待下一个数据块,这永远不会到来。所以客户需要知道什么时候完成。它可以知道的唯一方法是服务器是否将该信息放入数据流中。

一种方法是在文件之前发送长度。一种标准化的方法是使用netstring协议。您可以找到为您执行此操作的库,但手动操作非常简单。或者可能做一些更像 HTTP 的事情,其中​​标头仅由换行符分隔,并由空行与正文分隔;那么您可以将socket.makefile其用作您的协议实现。甚至是二进制协议,您只需将长度作为四个字节发送。

我们在这里还可以解决另一个问题:send(reply)不一定发送完整的回复;它发送从 1 个字节到整个内容的任何地方,并返回一个数字,告诉您发送了什么。对此的简单解决方法是使用sendall(reply),它保证发送所有内容。

最后:您的服务器期望每个人都recv将获得一个命令,如send. 但是套接字不是那样工作的。套接字是字节流,而不是消息流;没有什么可以阻止recv得到,比如说,只有半个命令,然后你的服务器就会崩溃。所以,你也需要在这个方向上的某种协议。同样,您可以使用网络字符串、换行符分隔的消息或二进制长度前缀,但您必须做一些事情

(上面链接的博客文章有使用二进制长度前缀作为协议的非常简单的示例代码。)

于 2013-11-15T00:06:03.387 回答
0

你可以做for line in file.readlines()

于 2013-11-15T00:37:09.920 回答