Haskell默认io缓冲

时间:2013-10-22 14:36:23

标签: haskell buffering xinetd

昨天我为我的学生写了一个小小的xinetd练习:做一个反向回音程序。

为了学习新东西,我试图实现一个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

如果我从xinetd(BlockBuffering Nothing)运行我的程序,我已经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 个答案:

答案 0 :(得分:11)

它不是特定于Haskell(例如标准C库做同样的事情)。 传统上,如果文件描述符对应于终端,则缓冲设置为行模式,否则设置为阻止模式。 isatty(3)函数可以检查文件描述符类型 - 不确定它是否导出到System.IO

是的,如果你依赖它,你需要手动设置缓冲模式。

顺便说一句,您可以通过以cat | ./prog | cat运行程序来欺骗系统并在命令行中强制阻止缓冲。

答案 1 :(得分:5)

GHC运行时系统在选择默认缓冲时会尝试变得聪明。如果看起来stdin和stdout直接连接到终端,它们将是行缓冲的。如果看起来它们与其他东西相连,则它们是块缓冲的。如果您想要使用不直接来自终端的逐行输入来运行程序,则可能会出现问题。例如,我认为cat | your-program的行为与your-program的行为不同。

  

如果我想用两种运行方法编写一个工作程序,我是否必须手动设置缓冲?