先警告一下:出于好奇目的,我在这里进行了一些黑客活动。我没有具体的原因去做下面的事情!
以下是在MacOS 10.12.5
上使用Python 2.7.13
完成的
我正在使用python进行黑客活动,我想知道如果我使stdout
无阻塞会发生什么有趣的事情。
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
调用 fcntl
的操作一定成功。然后,我尝试写入大量数据(大于OSX管道的最大缓冲区大小-即65536字节)。我以各种方式尝试,并获得不同的结果,有时是异常,有时似乎是硬性失败。
情况1fcntl.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
第三案例
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
,有时则不会抛出任何异常并且只会看到 "Slept"。似乎通过 print
"Slept" 我没有收到 Case 2 中的错误信息。
Case 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或系统级别上做错了什么根本性的事情吗?
似乎当写入已经失败时太早写入stdout会导致错误消息。该错误似乎不是异常。不知道它来自哪里。
N.B. 我可以用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;
}
os.write
可能会在写入完成之前返回,由于这会结束您的简单测试程序,因此sys.stdout
也可能在写入完成之前关闭。请注意,您的C程序等待(usleep(1000)
),而您的Python代码没有。 - chepnertime.sleep(1)
,但它没有任何区别:( - Andrew Parker