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

我不确定您所说的“服务器不会响应它”是什么意思?我猜您希望服务器在客户端断开连接后关闭。如果是这样,这不是库的意图:只要它们继续进入,它就会继续以无限循环的方式连接服务器。使用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 回答
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 回答