如何正确关闭网络连接的网络连接?

时间:2013-02-11 10:07:20

标签: haskell conduit network-connection

要了解conduit库的基础知识,我使用network-conduit创建了一个简单的echo服务器:

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

但问题仍然存在。我做错了什么?

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分: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()