Haskell tcp服务器,fd太大错误

时间:2017-04-13 14:33:08

标签: sockets haskell tcp

我一直在尝试为Go客户端编写Haskell服务器。对于Haskell TCP服务器,我只是使用Network.Socket。每当我尝试运行hWaitForInput时,我都会收到此错误:

fdReady: fd is too big.

这是服务器代码 -

connHandler :: (Socket, SockAddr) -> IO()
connHandler (sock, _) = do
  putStrLn "Starting Handler"
  handle <- socketToHandle sock ReadWriteMode
  hSetBuffering handle LineBuffering
  hPutStrLn handle "Hello Client!"
  putStrLn "Waiting for Input"
  success <- hWaitForInput handle (1000*10)
  putStrLn "Wait done"
  if success
      then do
          putStrLn "Client timed out"
      else do
          msg <- hGetLine handle
          putStrLn msg
  hClose handle

Go客户端正在接收并打印服务器的消息(“Hello Client!”),但是haskell服务器在打印“Waiting for Input”后立即抛出错误

2 个答案:

答案 0 :(得分:3)

你没有做错任何事。您看到的特定错误消息仅显示在Windows上运行的GHC&gt; = 8.0.2,并表示他们试图在非Windows体系结构上解决的内部GHC函数fdReady中的错误/限制但是在Windows上没有固定。 (不要觉得太嫉妒 - 非Windows体系结构上的“修复”目前也已破坏并崩溃。)尝试早期版本的GHC可能无济于事 - 它仍然会导致错误,但是错误信息会有所不同。

问题出现了:在Windows上,内部函数fdReady使用select()系统调用来轮询文件描述符以获取套接字,而select仅限于某个最大数值。它可以轮询的文件描述符。看起来这个值的Windows默认值非常低(64),但可以在编译时增加(编译 GHC 的时间,遗憾的是,不是GHC编译程序的时间)。

如果添加以下行:

hShow handle >>= putStrLn

hWaitForInput之前,您应该看到为套接字打印的一些调试信息,包括loc=<socket: nnn>,其中nnn是文件描述符。这可以帮助您验证您是否看到导致问题的文件描述符大于64。

如果是这种情况,我建议您提交GHC错误,看看是否可以修复它。

答案 1 :(得分:2)

作为替代/解决方法,您可以尝试在一个线程中读取一行,在另一个线程中读取一个计时器。

putStrLn "Waiting for Input"
msgMVar <- newEmptyMVar
tid <- forkIO $ hGetLine handle >>= putMVar msgMVar
maybeExn <- waitTimeout tid (1000*10)
case maybeExn of
    Nothing -> do
        killThread tid
        putStrLn "Client timed out"
    Just (Just _) ->
        putStrLn "Exception"
    _ -> do
        msg <- takeMVar msgMVar
        putStrLn msg
hClose handle

这确实有不同的行为(可以在读取行中间超时)而不是代码(如果可以读取单个字节,则永远不会超时),即使行不完整也是如此。