簡體   English   中英

Haskell TCP服務器,FD太大錯誤

[英]Haskell tcp server, fd is too big error

我一直在嘗試為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”后立即拋出錯誤。

你沒有做錯任何事。 您看到的特定錯誤消息僅在Windows上運行的GHC> = 8.0.2時出現,並且表示內部GHC功能fdReady中的錯誤/限制,他們已嘗試在非Windows體系結構上解決這些問題,但未解決視窗。 (不過,不要嫉妒–非Windows體系結構上的“修復”目前已損壞並崩潰。)嘗試使用較早版本的GHC可能無濟於事–仍然會導致錯誤,但是錯誤消息將有所不同。

這就是問題所在:在Windows上,內部函數fdReady使用select()系統調用輪詢套接字的文件描述符,而select fdReady將其輪詢的文件描述符限制為某個最大數值。 它看起來像Windows默認這個值是相當低(64),但是可以在編譯時增加(GHC編譯,不幸的是,沒有的時候GHC編譯程序的時間)。

如果添加行:

hShow handle >>= putStrLn

hWaitForInput之前,您應該看到為套接字打印了一些調試信息,包括loc=<socket: nnn> ,其中nnn是文件描述符。 這可以幫助您驗證是否看到了大於64的文件描述符,從而導致了問題。

如果是這種情況,我建議您提交GHC錯誤,以查看是否可以修復它。

作為一種替代方法/解決方法,您可以嘗試在一個線程中讀取一行,在另一個線程中讀取計時器。

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

但是,這確實具有與您的代碼不同的行為(可能在讀取行中間超時)(即使行未完成,如果可以讀取單個字節,也永遠不會超時)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM