Question

To learn the basics of conduit library, I used network-conduit to make a simple echo server:

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

It does what I wanted, but when the client closes its part of the connection, the server is still waiting for input instead of writing out any remaining data and closing its sending part of the connection too:

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

I tried removing echo and do just

echoApp appData = appSource appData $$ appSink appData

but the problem is still there. What am I doing wrong?

Was it helpful?

Solution

I'm not sure what you mean by "the server won't respond to it"? I'd guess you're expecting the server to shut down after the client disconnects. If so, that's not the intention of the library: it continues to server connections in an infinite loop as long as they continue coming in. Using addCleanup, you can see that the individual connection handlers do in fact terminate, e.g.:

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)

OTHER TIPS

It turned out that the problem wasn't with network-conduit, that part works correctly. The problem was with nc, which doesn't close its sending part of the socket when it sends all the data. I made a testing python script and it works against the server as expected:

#!/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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top