【问题标题】:Can I get a socket.makefile to have the same read semantics as a regular file?我可以让 socket.makefile 具有与常规文件相同的读取语义吗?
【发布时间】:2011-10-20 06:30:16
【问题描述】:

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 参数的解释方式与内置 file() 函数的解释方式相同。” 但我的原始文件示例即使在我说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!"

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

【问题讨论】:

  • @BrandonRhodes 我相信这是关闭套接字sock.shutdown(SHUT_WR) 的另一种可行选择

标签: python file sockets io


【解决方案1】:

这里的问题是client.read()试图从当前位置读取到EOF,但是只有在对方关闭连接时才会出现socket的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

【讨论】:

  • 这个答案完全正确:文件 EOF 的概念等价物是套接字 close();这个答案应该被接受。
  • 如果您只读取可用数据,它还会挂起吗?我认为一旦 99 字节确实进入。读取将停止阻塞,因为它正在等待 w/e IO 给它 99 字节或 EOF。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-17
  • 2020-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多