我在 Haskell 中使用Network
andGloss
作为游戏服务器。它工作正常,除了客户端必须关闭服务器才能接收它发送的数据。我敢打赌,这是一个懒惰的例子......
极简服务器:
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
极简客户:
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
我启动服务器,等待 10 秒,然后启动客户端,等待 15 秒,看到服务器上没有任何反应,关闭客户端,看到“你好!” 突然出现在服务器上。我想要“你好!” 在客户端运行时出现在advance
通话中,否则我无法制作多人游戏(呜咽)!
但是,如果我将客户的代码更改为
main = loop Nothing
loop x = do
x' <- advance 0 x
getLine
服务器立即显示“你好!” 当客户在等待我的输入时。
正如另一个问题中所建议的那样,我尝试使用爆炸模式和hClose
:
-- ...
!str <- hGetContents hIn
hClose hIn
-- ...
这使得输出立即出现,而无需关闭客户端。那太棒了。但是,我打算使用字节串,因为我发送到服务器的数据是序列化的,所以我import qualified Data.ByteString as B
更改hGetContents
为B.hGetContents
,这使得问题再次出现。
这个问题确实是一个懒惰的例子。hGetContents
懒惰地读取 的所有内容Handle
,因此它仅在关闭时完成,当客户端中止连接时。相反,我使用hGetLine
它在每次遇到 a 时返回内容\n
,我将其用作end-of-message
标记。