我正在使用Haskell的Network
库创建一个简单的聊天服务器。服务器必须做两件事:
服务器和客户端定义为
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
?
答案 0 :(得分:3)
在hIsEOF
&#39; documentation中,我发现了以下内容:
注意:hIsEOF可能会阻止,因为它必须尝试从中读取 流以确定是否还有更多数据要读取。
我不会预料到这一点。我想知道hReady
或hGetBufNonBlocking
是否更好?我从来没有尝试过Haskell中的整个非阻塞IO位。