Perl
讀取 STDIN 超時
我想閱讀 STDIN,但最多 5 秒。之後,我想處理我到目前為止讀過的數據。
select
似乎正是為此而設計的:等到有輸入或超時。如果有輸入,我應該只讀取那個非阻塞的。
所以我認為這會起作用:
#!/usr/bin/perl -w use strict; use Fcntl; open(my $in, "<&", "STDIN") or die; my $buf = ""; my $readsize = 10; # Make $in non-blocking fcntl($in, &F_SETFL, fcntl($in, &F_GETFL, 0) | &O_NONBLOCK); while(not eof($in)) { my $starttime = time(); my $rin = my $win = my $ein = ''; vec($rin, fileno($in), 1) = 1; while(time() < $starttime + 5 and length $buf < $readsize) { # Wait up to 5 seconds for input select($rin, $win, $ein, $starttime + 5 - time()); # Read everything that is available in the inputbuffer while(read($in,$buf,$readsize,length $buf)) {} } print "B:",$buf; $buf = ""; }
當執行時:
(echo block1;sleep 1; echo block1; sleep 6;echo block2)| perl nonblockstdin.pl
塊合併在一起。它們應該是兩個塊,因為塊 2 會在 6 秒後開始。
我究竟做錯了什麼?
一些問題:
- 設置
O_NONBLOCK
會影響打開的文件描述,而不僅僅是文件描述符。例如,如果你執行that-script; cat
,你會看到cat: -: Resource temporarily unavailable
,因為cat
’s stdin 變成了非阻塞的- 如果您使用非阻塞 I/O,
read()
如果此時沒有輸入並且設置了 eof,則係統呼叫會返回 EAGAIN 錯誤。perl
的eof()
呼叫read()
並暗示進行緩衝 I/O。您不能真正將其用於非阻塞 I/O。在您的範例中,第一個block1
被讀取eof()
,然後select()
等待sleep 1
,第二個block1
被讀取read()
,返回兩個block1
s。在這裡,您最好使用阻塞 I/O 並使用
alarm()
例如超時。如果使用非阻塞 I/O 和select()
,請不要使用eof()
和使用sysread()
,如果事先設置,read()
請確保在退出時清除標誌(在標準輸入上設置仍然是一個壞主意,因為標準輸入可以與其他程序共享)。O_NONBLOCK``O_NONBLOCK