【发布时间】:2017-12-10 10:18:40
【问题描述】:
事先警告:出于好奇,我在这里闲逛。我没有具体的理由去做我在下面做的事情!
以下是在Python 2.7.13MacOS 10.12.5上完成的
我正在使用 python 进行黑客攻击,我想看看如果我让 stdout 非阻塞会发生什么会很有趣
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
对fcntl 的调用肯定是成功的。然后我尝试写入大量数据(大于 OSX 上管道的最大缓冲区大小 - 即 65536 字节)。我以多种方式做到这一点并得到不同的结果,有时是例外,有时似乎是一个艰难的失败。
案例 1
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
sys.stdout.write("A" * 65537)
except Exception as e:
time.sleep(1)
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
这总是抛出异常Caught: [Errno 35] Resource temporarily unavailable。我觉得有道理。更高级别的文件对象包装器告诉我写调用失败。
案例 2
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
sys.stdout.write("A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
这有时会抛出异常 Caught: [Errno 35] Resource temporarily unavailable 或者有时没有捕获到异常,我看到以下输出:
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
案例 3
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
sys.stdout.write("A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
print "Slept"
这有时会引发异常 Caught: [Errno 35] Resource temporarily unavailable 或者有时没有捕获到异常,我只看到“睡眠”。看来printing "Slept" 我没有收到案例 2 的错误消息。
案例 4
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
os.write(sys.stdout.fileno(), "A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
总是好的!
案例 5
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
try:
print os.write(sys.stdout.fileno(), "A" * 65537)
except Exception as e:
print "Caught: {}".format(e)
# Safety sleep to prevent quick exit
time.sleep(1)
这有时可以,有时会打印close failed in file object destructor 错误消息。
我的问题是,为什么在 python 中会这样失败?我在这里做的事情从根本上是不好的 - 无论是使用 python 还是在系统级别?
似乎以某种方式在写入已经失败时过早写入标准输出会导致错误消息。该错误似乎不是异常。不知道它来自哪里。
注意我可以用 C 编写等效的程序,并且可以正常工作:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/fcntl.h>
#include <unistd.h>
int main(int argc, const char * argv[])
{
const size_t NUM_CHARS = 65537;
char buf[NUM_CHARS];
// Set stdout non-blocking
fcntl(fileno(stdout), F_SETFL, O_NONBLOCK);
// Try to write a large amount of data
memset(buf, 65, NUM_CHARS);
size_t written = fwrite(buf, 1, NUM_CHARS, stdout);
// Wait briefly to give stdout a chance to be read from
usleep(1000);
// This will be written correctly
sprintf(buf, "\nI wrote %zd bytes\n", written);
fwrite(buf, 1, strlen(buf), stdout);
return 0;
}
【问题讨论】:
-
我认为的问题是,对于非阻塞 IO,对
os.write的调用可以在写入完成之前返回,并且由于这结束了您的简单测试程序,sys.stdout也可以在写入完成之前关闭。请注意,您的 C 程序会等待 (usleep(1000)),而您的 Python 代码则不会。 -
感谢您的回复。我应该发布更完整的 python 代码 sn-p。写电话后我有一个
time.sleep(1),这没什么区别:( -
你的操作系统是什么?您可以尝试在
strace之类的名称下运行 Python,然后查看执行了哪些系统调用。 -
让我更新一下帖子,因为我可以澄清一些事情。各种调用的行为略有不同。
-
@Andrew Parker 使用延迟而不是 fflush。实际上有趣的想法。它来自一些 arduino 经验吗? ://
标签: python c posix nonblocking fcntl