16

昨天给同学们写了一个xinetd小练习:做一个反向回显程序。

为了学习新东西,我尝试实现一个 Haskell 解决方案。微不足道的main = forever $ interact reverse行不通。我经历了这个问题并做了一个更正的版本:

import Control.Monad
import System.IO
 
main = forever $ interact revLines
 
revLines = unlines . map (reverse) . lines 

但是这个更正的版本也不起作用。我阅读了缓冲文档并使用了各种设置。如果我设置NoBufferingor LineBuffering,我的程序可以正常工作。最后我打印出标准输入和标准输出的默认缓冲模式。

import System.IO

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

如果我BlockBuffering Nothing从 xinetd( ) 运行我的程序,echo "test" | nc localhost 7但从 cli 我有LineBuffering

  • 关于缓冲,xinetd tcp 服务和 cli 程序有什么区别?
  • 如果我想用两种运行方法编写一个工作程序,我是否必须手动设置缓冲?

编辑:谢谢大家的有用答案。

我接受了 blaze 给出的答案,他用 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 
4

2 回答 2

12

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

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

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

于 2013-10-22T15:07:47.157 回答
6

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

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

是的。

于 2013-10-22T15:10:47.423 回答