Haskell default io buffering

我的未来我决定 提交于 2019-12-12 09:33:14

问题


Yesterday i wrote a little xinetd exercise for my students: make a reverse echo program.

To learn something new, i tried to implement a Haskell solution. The trivial main = forever $ interact reverse does not work. I went through this question and made a corrected version:

import Control.Monad
import System.IO

main = forever $ interact revLines

revLines = unlines . map (reverse) . lines 

But this corrected version also doesn't work. I read the buffering documentation and played with the various settings. If i set NoBuffering or LineBuffering, my program works correctly. Finally i printed out the default buffering modes for stdin and stdout

import System.IO

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

I've got BlockBuffering Nothing if i run my program from xinetd(echo "test" | nc localhost 7) but from cli i've got LineBuffering

  • What is the difference between a xinetd tcp service and a cli program, regards to buffering?
  • Do i have to set manually the buffering if i want to write a working program with both running method?

Edit: Thank you all for the helpful answers.

I accept the answer which was given by blaze, he give me a hint with isatty(3). I went through again the System.IO documentation and found the hIsTerminalDevice function, with wich i am able to check the connection of the handle.

For the record, here is my final program:

{-# OPTIONS_GHC -W #-}

import System.IO

main = do
  hSetBuffering stdin LineBuffering
  hSetBuffering stdout LineBuffering

  interact revLines

revLines = unlines . map (reverse) . lines 

回答1:


It's not specific to Haskell (e.g. the standard C library does the same thing). Traditionally, if a file descriptor corresponds to the terminal, buffering is set to line mode, otherwise to block mode. File descriptor type can be checked by the isatty(3) function -- not sure if it is exported to System.IO.

And yes, you need to set buffering mode manually if you depend on it.

By the way, you can cheat the system and force block buffering in the command line by running your program as cat | ./prog | cat.




回答2:


The GHC runtime system tries to be clever when it chooses the default buffering. If it looks like stdin and stdout are directly connected to terminal, they will be line-buffered. If it looks like they are connected to something else, they are block-buffered. This can be problematic if you want to run a program with line-by-line input that doesn't come directly from a terminal. For example, I think that cat | your-program behaves differently from just your-program.

Do i have to set manually the buffering if i want to write a working program with both running method?

Yes.



来源:https://stackoverflow.com/questions/19520885/haskell-default-io-buffering

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!