2013-02-11 125 views
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 

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

回答

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) 
+0

谢谢迈克尔。我期待服务器在远程客户端关闭发送一半时停止读取套接字。事实证明,问题出在'nc',而不是管道库。 'nc'不关闭发送端的一半。 – 2013-02-11 12:26:13

+0

只是好奇什么样的netcat被使用 - openbsd的或gnu的重写? – 2013-02-11 15:29:34

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()