2017-04-13 36 views
1

我一直在試圖寫一個圍棋客戶端哈斯克爾服務器。對於Haskell TCP服務器,我只是使用Network.Socket。每當我嘗試運行hWaitForInput,我收到此錯誤:哈斯克爾TCP服務器,fd是太大錯誤

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 

轉到客戶端接收和打印服務器的消息(「你好客戶!」)但哈斯克爾服務器打印「等待輸入」

回答

3

你是不是做錯了什麼之後引發錯誤。您看到的特定錯誤消息僅在GHC> = 8.0.2的Windows上運行,並且表示他們嘗試在非Windows體系結構上解決的內部GHC函數fdReady中的缺陷/限制,但尚未解決視窗。 (不要覺得太嫉妒,儘管 - 非Windows體系結構上的「修復」目前也被破壞並崩潰。)嘗試早期版本的GHC可能無濟於事 - 它仍然會導致錯誤,但錯誤信息會有所不同。

這裏的問題:在Windows上,內部功能fdReady使用select()系統調用來輪詢文件描述符插座,並select被限制爲文件描述符它可以輪詢一定的最大數值。它看起來像這個值的Windows默認值很低(64),但可以在編譯時增加(編譯時間爲GHC,不幸的是,不是GHC編譯您的程序的時間)。

如果您添加一行:

hShow handle >>= putStrLn 

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

如果是這樣的話,我會建議在提出GHC的錯誤,看看你是否可以把它修好。

+1

我只是[開了一個bug(https://ghc.haskell.org/trac/ghc/ticket/14530#ticket)。讓我們看看會發生什麼...... –

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 

這確實有不同的行爲比你的代碼(可以在閱讀一行中間超時)(永不超時如果單個字節可以讀出,即使該線不完整),雖然。

+0

我在想,殺死正在執行'hGetLine'的線程是否會在Windows上工作。我目前無法做到這一點,正如[這個問題]所述(https://stackoverflow.com/questions/47507586/killing-a-thread-waiting-on-hgetline-from-a-socket-windows)。 –