为什么在以下示例中不应使用缓冲?

Car*_*ate 2 networking buffer haskell

我正在阅读本教程:http: //www.catonmat.net/blog/simple-haskell-tcp-server/ 了解Haskell网络模块的基础知识.他写了一个名为sockHandler的小函数:

sockHandler :: Socket -> IO ()
sockHandler sock = do
    (handle, _, _) <- accept sock
    hSetBuffering handle NoBuffering
    forkIO $ commandProcessor handle
    sockHandler sock
Run Code Online (Sandbox Code Playgroud)

接受连接,并将其分配给新线程.在打破代码的同时,他说:

"接下来我们使用hSetBuffering将客户端套接字句柄的缓冲模式更改为NoBuffering,因此我们没有缓冲惊喜."

但是没有详细说明这一点.他在谈论什么惊喜?我谷歌了,看到了一些安全文章(我猜测与被拦截的缓存有关),但似乎与本教程的内容没什么关系.

有什么问题?我想到了,但我认为我没有足够的网络经验来填补空白.

谢谢.

chi*_*chi 5

为了便于说明,假设协议允许服务器向客户端查询某些信息,例如(以下是愚蠢的例子)

 hPutStr sock "Please choose between A or B"
 choice <- hGetLine sock
 case decode choice of
    Just A -> handleA
    Just B -> handleB
    Nothing -> protocolError
Run Code Online (Sandbox Code Playgroud)

一切看起来都很好......但服务器似乎挂了.为什么?这是因为消息并非真正通过网络发送hPutStr,而只是插入本地缓冲区.因此,另一端永远不会收到查询,因此不会回复,导致服务器卡在其读取中.

这里的解决方案是hFlush sock在读取之前插入.这必须手动插入"右"点,并且容易出错.更懒的选择是完全禁用缓冲 - 这更安全,尽管它会严重影响性能.