14

Haskell のゲーム サーバーにNetworkandを使用しています。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

ミニマリストのクライアント:

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 秒待って、サーバーで何も起こらないことを確認し、クライアントを閉じます。「Hello!」が表示されます。サーバーに突然現れます。「こんにちは!」クライアントの実行中、advance通話中に表示されない場合、マルチプレイヤー ゲームを作成できません (すすり泣く)!


ただし、クライアントのコードを次のように変更すると

main = loop Nothing
loop x = do
    x' <- advance 0 x
    getLine

サーバーはすぐに「Hello!」を表示します。クライアントが私の入力を待っている間。


別の質問で提案されているように、強打パターンとを使用しようとしましたhClose:

-- ...
!str <- hGetContents hIn
hClose hIn
-- ...

これにより、クライアントを閉じることなく、出力がすぐに表示されます。それは素晴らしいことです。しかし、サーバーに送信するデータはシリアル化されるため、バイト文字列を使用する予定です。そのため、にimport qualified Data.ByteString as B変更hGetContentsするとB.hGetContents、問題が再発します。


問題は確かに怠惰の場合でした。hGetContentsのすべてのコンテンツを遅延して読み取るHandleため、クライアントが接続を中止したときに、それが閉じられたときにのみ終了します。代わりに、タグとして使用する にhGetLine遭遇するたびにコンテンツを返すを使用しました。\nend-of-message

4

3 に答える 3

9

私は完全に間違っているかもしれませんが、問題は hGetContents ではないでしょうか? 確かに、ソケットを介して送信されたコンテンツ全体が到着するまで待ってから、次の行 (印刷...) を開始する必要があります。hGetContents は、ソケットが閉じられるまで送信されたすべてのコンテンツを提供するように設計されています。hGetLine のようなものはすぐに終了する可能性があり、後でより多くのデータを送信するためにソケットを開いたままにすることができます。クライアントは hPutStr の代わりに hPutStrLn を使用できます。

于 2012-08-26T23:40:52.757 に答える
3

デフォルトでは行バッファー出力になりhPutStrます。そのため、バッファーをフラッシュするまで(行末を提供しない)何も出力されません。これを解決する方法は2つあります。

a)hFlush stdout出力をフラッシュしたいときはいつでも手動で呼び出します。

b)hSetBufferingバッファリングをに設定するために使用しますNoBuffering

これらの機能はすべてSystem.IOモジュールにあります。

編集:気にしないでください、私はあなたがクライアントのどこでそれをしたかを見ました。申し訳ありませんが、回答を撤回します。

于 2012-08-26T21:38:54.610 に答える
2

おそらく、アルゴリズム Nagleを無効にする必要があります。このコードを試してください:

import Network.Socket

setSocketOption sock NoDelay 1
于 2012-08-27T04:59:33.483 に答える