【发布时间】:2014-08-04 21:38:58
【问题描述】:
我正在使用 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?
【问题讨论】:
-
你能捕捉并打印出异常吗?您可以使用
Control.Exception.try来执行此操作:try (hIsEOF handle) :: IO (Either SomeException Bool) -
它没有通过尝试让我打印任何东西。如果我在
try ...之前放置一个打印语句,它会显示,但之后不会。 -
您链接的文档确实说“注意:hIsEOF 可能会阻塞,因为它必须尝试从流中读取以确定是否还有要读取的数据。”
-
如果
try阻塞,那么这意味着它不是一个例外。try旨在在出现异常时立即返回。这表明@ØrjanJohansen 是正确的,它阻止了从流中读取。
标签: haskell client-server handle