Haskell websockets 标头
Posted
技术标签:
【中文标题】Haskell websockets 标头【英文标题】:Haskell websockets header 【发布时间】:2015-03-18 15:41:37 【问题描述】:我正在尝试在 haskell 中读取 websockets 标头。
当前代码如下
import Network
import Network.Socket.Internal
import Text.Printf
import Control.Monad
import Control.Monad.IO.Class
import Data.Maybe
import Data.List
import Data.Digest.Pure.SHA (bytestringDigest, sha1)
import Text.Regex
import System.IO
port :: Int
port = 8080
bufferLength :: Int
bufferLength = 2048
keyRegex :: String
keyRegex = "Sec-WebSocket-Key: (.+)(\r)"
response :: String
response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nsec-websocket-accept: changethis\r\n\r\n"
guidString :: String
guidString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
talk :: MonadIO m => Handle -> m String
talk handle = do liftIO $ hGetContents handle
main :: IO()
main = withSocketsDo $ do
sock <- listenOn (PortNumber (fromIntegral port))
printf "Listening on port %d\n" port
forever $ do
(handle, host, port) <- accept sock
printf "Accepted connection from %s: %s\n" host (show port)
hSetBuffering handle NoBuffering
putStrLn $ talk handle
代码报错
Main.hs:38:16:
Couldn't match type `[Char]' with `Char'
Expected type: String
Actual type: [String]
In the return type of a call of `talk'
In the second argument of `($)', namely `talk handle'
In a stmt of a 'do' block: putStrLn $ talk handle
如何打印标题字符串?谈话函数应该获取标题字符串并将其返回以进行打印。
【问题讨论】:
你的意思是talk handle >>= putStrLn
?
【参考方案1】:
talk handle
的返回类型为(MonadIO m => m String)
。
putStrLn
的类型为 String -> IO ()
或 [Char] -> IO ()
。
[]
是一个单子。
putStrLn
需要一个字符列表,但它的值是 (MonadIO m => m String)
。
m
变成一个列表,putStrLn
得到一个 [String]
类型的值,这是错误。
正如@Zeta 建议的那样,改用talk handle >>= putStrLn
:
>>=
是允许使用另一个计算的结果继续计算的运算符。在您的情况下,您可以阅读talk handle >>= putStrLn
,如下所示:
talk handle -- first compute it
>>= putStrLn -- then take string from result of `talk handle` and print it
putStrLn $ talk handle
不会出现任何错误:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
talk handle :: MonadIO m => m String
(>>=) (talk handle) :: MonadIO m => (String -> m b) -> m b
putStrLn :: String -> IO ()
(>>=) (talk handle) putStrLn :: IO () -- `m` becomes `IO`
编辑:
在这里你可以找到IO
monad 的介绍:LYHFGG, Input and Output
在这里您可以找到对 monad 的一般介绍:LYHFGG, A Fistful of Monads。
您应该了解Functor
和Applicative
才能阅读A Fistful of Monads
。无论如何,您都可以在书的内容中找到它。
【讨论】:
谢谢。我将如何将谈话结果存储在字符串变量中? 或将其传递给 String 类型的函数 -> String? @haskellstuff Haskell 中没有变量。您可以将talk
的结果绑定到一个名称,就像您对sock
所做的那样,然后像字符串常量一样使用它。或者您可以将其传递给类型为 String -> String
的函数,然后在那里访问它。但是,要做到这一点,首先您需要将talk
的结果绑定到一个名称,然后通过参数将其传递给函数,或者直接使用绑定运算符,如talk handle >>= \ s -> ... let r = f s ...
。这里,s
是 talk handle
的结果,f
是 String -> String
类型的函数。
@haskellstuff 你不能只访问talk
的结果,因为它在IO
monad 内部。我编辑了问题以参考有关 monad 的良好资源。以上是关于Haskell websockets 标头的主要内容,如果未能解决你的问题,请参考以下文章
使用Cro :: WebSocket :: Client添加授权或标头?
“发送非空 'Sec-WebSocket-Protocol' 标头但未收到响应” Django 频道
Spring WebSocket:由于升级标头无效,握手失败:null