Haskell中的套接字编程:putStrLn / hPutStrLn的行为不符合预期

时间:2016-05-10 15:53:31

标签: sockets haskell io

我目前正在尝试在Haskell中编写一个玩具服务器,并以https://wiki.haskell.org/Implement_a_chat_server为例介绍套接字编程。

我遇到的问题是putStrLnhPutStrLn的行为不符合我的预期。这篇文章底部的代码是一个完整的例子,展示了我的问题,编译和运行没有问题如下:

$ ghc -main-is TestServer.main TestServer.hs

$ ./TestServer

服务器接受端口4242上的telnet连接,如下所示:

$ telnet localhost 4242

然后提示用户输入他们的名字。输入后,用户应收到以下消息:

欢迎,[用户名]!

但是接收消息

!elcome,[username]

请注意,感叹号似乎从字符串的末尾移开并替换“W”。用户名的长度没有区别,结果是相同的。

此外,运行服务器的终端应显示用户的名称,如下所示:

[用户名]已加入服务器。

但显示:

已加入服务器。

用户名似乎是空字符串。但是,如果我们只是替换

putStrLn (userName newUser)

为行

putStrLn ((userName newUser) ++ " has joined the server.")

正确显示用户名。我有点不知道为什么我遇到这些问题(与上面相关的例子编译得很好,并且putStrLn / hPutStrLn没有这样的问题。我确信它是一种非常微妙的东西。

以上是上述代码:

-- TestServer.hs
module TestServer where

import Control.Concurrent
import Network.Socket
import System.IO

type User = (Handle, String)

userName :: User -> String
userName (_, name) = name

main :: IO ()
main = do
    sock <- socket AF_INET Stream 0
    setSocketOption sock ReuseAddr 1
    bind sock (SockAddrInet 4242 iNADDR_ANY)
    listen sock 2
    socketLoop sock []

socketLoop sock users = do
    (uSock, _)      <- accept sock
    uHandle         <- socketToHandle uSock ReadWriteMode
    hSetBuffering uHandle NoBuffering
    newUser         <- initUser uHandle

    putStrLn ((userName newUser) ++ " has joined the server.")

    socketLoop sock (newUser:users)

initUser :: Handle -> IO User
initUser handle = do
    hPutStr handle "Please enter your name: "
    name <- hGetLine handle
    let user = (handle, name) in do
        hPutStrLn handle ("Welcome, " ++ name ++ "!")
        return user

1 个答案:

答案 0 :(得分:0)

我将问题标记为重复,但我希望发布我的解决方案,该问题可能会证明有用,因为原始问题不包含明确的解决方案。

我将对hGetLine handle的调用打包如下:

sanitizeInput :: Handle -> IO String
sanitizeInput handle = do
    input <- hGetLine handle
    return (sanitize input)

badChars :: [Char]
badChars = ['\r']

sanitize :: String -> String
sanitize = filter (\x -> not (elem x badChars))