这里的问题与套接字无关,也与文件的大小无关。执行此操作时:for line in f:
reply = f.read()
for line in f尝试一次读取文件的一行,然后对每一行尝试读取整个文件。那不行。在
如果您没有收到这个错误(在很多情况下不会出现这种错误),第一次通过循环时,您将读取并忽略第一行,然后读取并发送除第一行之外的所有内容(或者,可能,除了第一行之外的所有内容,例如4KB),然后循环就完成了。在
你想要的是其中之一:
^{pr2}$
……或者# no for loop
reply = f.read()
同时,在客户端,您只执行一个recv。这将得到第一个4K(或任何socksize)或更少,然后您再也不会收到其他任何东西。在
你需要的是一个循环。像这样:while True:
data = client_socket.recv(socksize)
print data
但现在你有了一个新的问题。一旦文件完成,客户机将永远坐在那里等待下一个数据块,而下一个数据块永远不会出现。所以客户需要知道何时完成。唯一的方法是服务器是否将这些信息放入数据流中。在
一种方法是发送文件之前的长度。一种标准化的方法是使用netstring协议。你可以找到为你做这件事的库,但它很简单,可以手工完成。或者做一些更像HTTP的操作,其中头只由换行符分隔,并用一个空行与主体分隔;然后可以使用socket.makefile作为协议实现。或者甚至是二进制协议,只需发送4个字节的长度。在
还有一个问题我们可以在这里解决:send(reply)不一定要发送整个回复;它发送1个字节到整个内容的任何位置,并返回一个数字,告诉您发送了什么。解决这个问题的简单方法是使用sendall(reply),它保证发送所有的文件。在
最后:您的服务器期望每个recv将得到一个由send发送的命令。但是插座不是这样工作的。Sockets are byte streams, not message streams;没有什么可以阻止recv获得,比如说,只需要半个命令,那么服务器就会崩溃。所以,你也需要某种协议。同样,您可以使用netstring、换行分隔消息或二进制长度前缀,但您必须做一些的事情。在
(上面链接的博客文章有一个非常简单的示例代码,用于将二进制长度前缀用作协议。)