Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Simple Telnet client in haskell using Data.Conduit (0.4.x.y)
import Control.Concurrent (forkIO, killThread)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans.Resource
import Data.Conduit
import Data.Conduit.Binary
import Network (connectTo, PortID (..))
import System.Environment (getArgs, getProgName)
import System.IO
main :: IO ()
main = do
args <- getArgs
case args of
[host, port] -> telnet host (read port :: Int)
_ -> usageExit
where
usageExit = do
name <- getProgName
putStrLn $ "Usage : " ++ name ++ " host port"
telnet :: String -> Int -> IO ()
telnet host port = runResourceT $ do
(releaseSock, hsock) <- allocate (connectTo host $ PortNumber $ fromIntegral port) hClose
liftIO $ mapM_ (`hSetBuffering` LineBuffering) [ stdin, stdout, hsock ]
(releaseThread, _) <- allocate (forkIO $ runResourceT $ sourceHandle stdin $$ sinkHandle hsock) killThread
sourceHandle hsock $$ sinkHandle stdout
release releaseThread
release releaseSock

Thanks for sharing this example. I stumbled upon it while learning about implementing telnet chat servers with Haskell. I know it has been several years since you posted this example, but out of curiousity, did you encounter any problems with this client truncating the output? I built a chat-server based on an example that I found on HaskellWiki. The server works well with the telnet client supplied with OSX. I also produced a telnet client using your example, and I found that the client truncates the output. For example, if a user enters "Hello World", the output is "Hello Worl". So, the last character is always truncated.

I have been digging into the packages used in the example to determine if something might be truncating the output. My thought is that perhaps one of the input or output handles is truncating the bytestring from stdin? But I am fairly new to Haskell, so it is a bit above my head. If you have any thoughts, please let me know.

Running with GHC, the code above gives a conflict on line 26.

telnet.hs:26:14: error:
    Ambiguous occurrence ‘mapM_’
    It could refer to either ‘Prelude.mapM_’,
                             imported from ‘Prelude’ at telnet.hs:1:1
                             (and originally defined in ‘Data.Foldable’)
                          or ‘Data.Conduit.Binary.mapM_’,
                             imported from ‘Data.Conduit.Binary’ at telnet.hs:5:1-26

Replacing it with the following solves the issue:

    liftIO $ Prelude.mapM_ (`hSetBuffering` LineBuffering) [ stdin, stdout, hsock ]

Cheers !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment