3

conduitライブラリ の基本を学ぶためにnetwork-conduit、単純なエコー サーバーを作成していました。

import Control.Monad.IO.Class
import qualified Data.ByteString.Char8 as BS
import Data.Conduit
import Data.Conduit.Network

-- A conduit that print the input it receives on the console
-- and passes it through.
echo :: (MonadIO m) => Conduit BS.ByteString m BS.ByteString
echo = do
    yield (BS.pack "Anything you type will be echoed back.\n")
    -- Print the received data to the console as well:
    awaitForever (\x -> liftIO (BS.putStr x) >> yield x)

echoApp :: (MonadIO m) => Application m
echoApp appData = appSource appData $= echo $$ appSink appData

-- Listen on port 4545:
main :: IO ()
main = runTCPServer (serverSettings 4545 HostAny) echoApp

それは私が望んでいたことを行いますが、クライアントが接続の一部を閉じると、サーバーは残りのデータを書き出して接続の送信部分も閉じるのではなく、入力を待っています。

$ nc localhost 4545 <<<"Hello world!"
Anything you type will be echoed back.
Hello world!

私は削除echoしてみました

echoApp appData = appSource appData $$ appSink appData

しかし、問題はまだあります。私は何を間違っていますか?

4

2 に答える 2

2

network-conduit問題は にあるのではなく、その部分は正しく動作することが判明しました。問題はnc、すべてのデータを送信するときにソケットの送信部分を閉じない にありました。テスト用の python スクリプトを作成しましたが、期待どおりにサーバーに対して動作します。

#!/usr/bin/env python
import socket

HOST = 'localhost'
PORT = 4545

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

s.sendall('Hello, world')
# This was missing in `nc`:
s.shutdown(socket.SHUT_WR);

print 'Received'
data = s.recv(1024)
while data:
    print data,
    data = s.recv(1024)

s.close()
于 2013-02-11T12:37:21.177 に答える
2

「サーバーが応答しない」とはどういう意味ですか? クライアントが切断された後、サーバーがシャットダウンすることを期待していると思います。もしそうなら、それはライブラリの意図ではありません: 接続が入ってくる限り無限ループでサーバー接続を続けます. を使用addCleanupすると、個々の接続ハンドラが実際に終了することがわかります.

echo :: (MonadIO m) => Conduit BS.ByteString m BS.ByteString
echo = addCleanup (const $ liftIO $ putStrLn "Stopping") $ do
    yield (BS.pack "Anything you type will be echoed back.\n")
    -- Print the received data to the console as well:
    awaitForever (\x -> liftIO (BS.putStr x) >> yield x)
于 2013-02-11T12:04:39.980 に答える