我目前正在尝试在Haskell中编写一个玩具服务器,并以https://wiki.haskell.org/Implement_a_chat_server为例介绍套接字编程。
我遇到的问题是putStrLn
和hPutStrLn
的行为不符合我的预期。这篇文章底部的代码是一个完整的例子,展示了我的问题,编译和运行没有问题如下:
$ 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
答案 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))