我可以让socket.makefile具有与常规文件相同的读取语义吗?

时间:2011-08-04 18:27:35

标签: python file sockets io

Python文件对象有一个read方法,它接受一个可选的size参数,该参数基本上是要返回的最大字节数。例如:

fname = "message.txt"
open(fname, "w").write("Hello World!")
print open(fname).read()   # prints the entire file contents
print open(fname).read(5)  # print "Hello"
print open(fname).read(99) # prints "Hello World!"

因此,即使我们的文件少于99个字符,对read(99)的调用也会立即返回所有可用数据。

我想在socket.makefile返回的文件对象上获得此行为。但如果我说:

import socket
ADDR = ("localhost", 12345)

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.bind(ADDR)
listener.listen(1)

client = socket.create_connection(ADDR)
cf = client.makefile("r+b", bufsize=0)

server, client_addr = listener.accept()
sf = server.makefile("r+b", bufsize=0)

sf.write("Hello World!")
sf.flush()
print cf.read(99)         # hangs forever

根据socket.makefile文档,“可选模式和bufsize参数的解释方式与内置文件()函数相同。”但我的原始文件示例有效即使我说open(fname, "r+b", 0),我也无法找到一种方法,使用套接字伪文件将所有可用数据返回到指定的字节数。

如果我只使用socket.recv

,这似乎非常有效
import socket
ADDR = ("localhost", 12345)

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.bind(ADDR)
listener.listen(1)

client = socket.create_connection(ADDR)
server, client_addr = listener.accept()

server.sendall("Hello World!")
print client.recv(99)           # prints "Hello World!"

那么有没有办法让这个工作socket.makefile,或者这种“高级”功能根本不可用?

编辑: Python 3.2似乎表现正常,但socket.makefile的参数语法似乎已经改变:

import socket
ADDR = ("localhost", 12345)

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.bind(ADDR)
listener.listen(1)

client = socket.create_connection(ADDR)
cf = client.makefile("rwb", buffering=0)

server, client_addr = listener.accept()
sf = server.makefile("rwb", buffering=0)

sf.write(b"Hello World!")
sf.flush()
print(cf.read(99))         # prints "Hello World!"

我还没有深入研究源代码,以找出这两个版本之间的区别,但这可能是一个提示。

1 个答案:

答案 0 :(得分:24)

这里的问题是client.read()尝试从当前位置读取到EOF,但套接字的EOF仅在另一方关闭连接时出现。另一方面,recv将返回任何准备好读取的数据(如果有的话),或者可能根据阻塞和超时设置阻止。

与此相比:

import socket
ADDR = ("localhost", 12345)

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.bind(ADDR)
listener.listen(1)

client = socket.create_connection(ADDR)
cf = client.makefile("r+b", bufsize=0)

server, client_addr = listener.accept()
sf = server.makefile("r+b", bufsize=0)

sf.write("Hello World!")
sf.flush()
sf.close()
server.close()
print cf.read(99)         # does not hang