为什么hIsEOF不会返回?

时间:2014-08-04 21:38:59

标签: haskell client-server handle

我正在使用Haskell的Network库创建一个简单的聊天服务器。服务器必须做两件事:

  • 每隔 n 向所有当前连接的客户端广播一条消息
  • 从发送到服务器的客户端接收任何消息。

服务器和客户端定义为

data Server = Server {
  sSocket :: Socket,
  sPort :: Port,
  sClients :: MVar (Set.Set ClientAddress)
  }

newtype ClientAddress = ClientAddress (Handle, HostName, PortNumber) 
                          deriving (Show)

通过运行以下函数构建服务器

startServer :: Port -> IO ThreadId -- 
startServer port = withSocketsDo $ do
  socket  <- listenOn $ PortNumber $ fromIntegral port  
  clients <- newMVar Set.empty
  let server = Server socket port clients
  forkIO $ forever $ do
    client@(handle, host, port) <- accept socket
    modifyMVar_ clients (\cs -> return $ Set.insert (ClientAddress client) cs)
    forkIO $ forever $ serve $ ClientAddress client
  forkIO $ forever $ sendServerUpdates 1000000 server

请注意,最后两行分叉两个不同的线程:第一个用于处理客户端连接和“提供”其消息,第二个用于将服务器广播发送到客户端。

向客户广播如下工作

sendServerUpdates :: Microsecond -> Server -> IO ()
sendServerUpdates frequency server = do
  withMVar (sClients server) (mapM_ sendServerUpdate)
  threadDelay frequency

sendServerUpdate :: ClientAddress -> IO ()
sendServerUpdate (ClientAddress (handle, host, port)) = do
  putStrLn "Sending update."

我遇到的问题是,从客户端接收消息似乎阻止了。我通过检查句柄是否包含内容来接收消息

serve :: ClientAddress -> IO ()
serve (ClientAddress (handle, host, port)) = do
  b <- hIsEOF handle
  putStrLn $ show $ b -- <-- It never makes it this far...

不幸的是,代码永远不会到第二行调用putStrLn。似乎hIsEOF遇到了一些例外,although the documentation doesn't seem to mention it

为什么我的代码会永久阻止hIsEOF

1 个答案:

答案 0 :(得分:3)

hIsEOF&#39; documentation中,我发现了以下内容:

  

注意:hIsEOF可能会阻止,因为它必须尝试从中读取   流以确定是否还有更多数据要读取。

我不会预料到这一点。我想知道hReadyhGetBufNonBlocking是否更好?我从来没有尝试过Haskell中的整个非阻塞IO位。