Haskell中的游戏服务器

L01*_*man 14 haskell network-programming lazy-evaluation

我使用Network,并Gloss在哈斯克尔游戏服务器.它工作正常,除了客户端必须关闭服务器以接收它发送的数据.我打赌这是一个懒惰的案例......

极简主义服务器:

import Network
import System.IO

main = do
    sock <- listenOn (PortNumber (fromIntegral 12345))
    loop sock

loop sock = do
    (hIn, _, _) <- accept sock
    str <- hGetContents hIn
    print str
    loop sock
Run Code Online (Sandbox Code Playgroud)

极简主义客户:

import Network
import System.IO
import Graphics.Gloss.Interface.IO.Game

main = playIO
    (InWindow "Test Multi" (500, 500) (500, 500))
    white
    60
    Nothing
    draw
    (\_ x -> return x)
    advance

draw Nothing = return blank
draw (Just x) = return (Text (show x))

advance _ Nothing = do
    hOut <- connectTo "000.000.0.0" (PortNumber (fromIntegral 12345))
    hSetBuffering hOut NoBuffering
    hPutStr hOut "Hello!"
    return (Just hOut)
advance _ x = return x
Run Code Online (Sandbox Code Playgroud)

我启动服务器,等待10秒,然后启动客户端,等待15秒,看到服务器上没有任何反应,关闭客户端,看到"你好!" 突然出现在服务器上.我想"你好!" 在客户端正在运行时,在advance通话中出现,否则我无法进行多人游戏(呜咽)!


但是,如果我将客户端的代码更改为

main = loop Nothing
loop x = do
    x' <- advance 0 x
    getLine
Run Code Online (Sandbox Code Playgroud)

服务员立即显示"你好!" 而客户端正在等待我的输入.


我按照另一个问题的建议尝试使用爆炸模式和hClose:

-- ...
!str <- hGetContents hIn
hClose hIn
-- ...
Run Code Online (Sandbox Code Playgroud)

这使得输出立即显示,而不会关闭客户端.那很棒.但是,我打算使用字节串,因为我向服务器发送的数据是系列化的,所以我import qualified Data.ByteString as B并更改hGetContentsB.hGetContents,这使得该问题再次出现.


问题确实是一种懒惰的情况.hGetContents懒惰读取所有内容Handle,因此只有当它关闭时,客户端才会中止连接.相反,我使用hGetLine它返回每次遇到a时的内容\n,我将其用作end-of-message标记.

And*_*ewC 9

我可能完全错了,但问题不是hGetContents?当然应该等到通过套接字发送的所有内容在下一行(打印...)开始之前到达.hGetContents 旨在为您提供在套接字关闭之前发送的所有内容.像hGetLine这样的东西可以直接终止,你可以让套接字打开以便稍后发送更多数据.然后,您的客户端可以使用hPutStrLn而不是hPutStr.