2013-10-22 104 views
11

昨天我爲我的學生寫了一個小小的xinetd練習:製作一個反向回聲程序。Haskell默認io緩衝

爲了學習新的東西,我試圖實現一個Haskell解決方案。微不足道的main = forever $ interact reverse不起作用。我通過this question去,並提出了修改後的版本:

import Control.Monad 
import System.IO 

main = forever $ interact revLines 

revLines = unlines . map (reverse) . lines 

但這個修改後的版本也不起作用。我讀了buffering documentation並且玩了各種設置。 如果我設置了NoBufferingLineBuffering,我的程序可以正常工作。最後我打印出來的stdin和stdout的默認緩衝模式

import System.IO 

main = do 
    hGetBuffering stdin >>= print 
    hGetBuffering stdout >>= print 

我有BlockBuffering Nothing如果我從運行的xinetd(echo "test" | nc localhost 7)我的計劃,但是從CLI我有LineBuffering

  • 是什麼一個xinetd tcp服務和一個cli程序之間的差異,是否考慮緩衝?
  • 如果我想用兩種運行方法編寫一個工作程序,是否必須手動設置緩衝?

編輯:謝謝大家的幫助的答案。

我接受火焰給出的答案,他給我一個提示isatty(3)。我再次通過了System.IO文檔,發現了hIsTerminalDevice函數,至此我能夠檢查句柄的連接。

爲了記錄在案,這裏是我的最終方案:

{-# OPTIONS_GHC -W #-} 

import System.IO 

main = do 
    hSetBuffering stdin LineBuffering 
    hSetBuffering stdout LineBuffering 

    interact revLines 

revLines = unlines . map (reverse) . lines 
+2

你不需要'永遠'在這裏。由於懶惰,'interact'將繼續等待輸入,並且對於來自'stdin'的每個完整行,它的反向將立即打印。 – tempestadept

+0

我認爲它的操作系統特定,但通常如果你有一個面向行的程序,那麼你可能會從'LineBuffering'中獲得最好的行爲。 –

+5

我做了很多抱怨不好的問題,所以我只想讚揚你。這是一個很好的問題。最小化代碼,明確指示重現您的問題,明確證明您自己取得了一些進展,並清晰地描述了您需要了解的進展情況。愉快。 –

回答

10

這不是具體到哈斯克爾(例如標準C庫做同樣的事情)。 傳統上,如果文件描述符對應於終端,則緩衝設置爲行模式,否則爲阻止模式。文件描述符類型可以通過isatty(3)函數檢查 - 不知道它是否導出到System.IO

是的,你需要手動設置緩衝模式,如果你依賴它。

順便說一下,您可以通過運行您的程序作爲cat | ./prog | cat來欺騙系統並在命令行中強制塊緩衝。

5

GHC運行時系統嘗試在選擇默認緩衝時很聰明。如果看起來stdin和stdout直接連接到終端,它們將被行緩衝。如果看起來他們連接到其他東西,他們是塊緩衝。如果您想要使用不是直接來自終端的逐行輸入來運行程序,則這可能會有問題。例如,我認爲cat | your-program的行爲不同於your-program

如果我想用兩種運行方法編寫工作程序,我必須手動設置緩衝嗎?

是。