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 &gt;&gt;= putStrLn 【参考方案1】:

talk handle 的返回类型为(MonadIO m =&gt; m String)

putStrLn 的类型为 String -&gt; IO ()[Char] -&gt; IO ()

[] 是一个单子。

putStrLn 需要一个字符列表,但它的值是 (MonadIO m =&gt; m String)

m 变成一个列表,putStrLn 得到一个 [String] 类型的值,这是错误。


正如@Zeta 建议的那样,改用talk handle &gt;&gt;= putStrLn

&gt;&gt;= 是允许使用另一个计算的结果继续计算的运算符。在您的情况下,您可以阅读talk handle &gt;&gt;= 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。

您应该了解FunctorApplicative 才能阅读A Fistful of Monads。无论如何,您都可以在书的内容中找到它。

【讨论】:

谢谢。我将如何将谈话结果存储在字符串变量中? 或将其传递给 String 类型的函数 -> String? @haskellstuff Haskell 中没有变量。您可以将talk 的结果绑定到一个名称,就像您对sock 所做的那样,然后像字符串常量一样使用它。或者您可以将其传递给类型为 String -&gt; String 的函数,然后在那里访问它。但是,要做到这一点,首先您需要将talk 的结果绑定到一个名称,然后通过参数将其传递给函数,或者直接使用绑定运算符,如talk handle &gt;&gt;= \ s -&gt; ... let r = f s ...。这里,stalk handle 的结果,fString -&gt; String 类型的函数。 @haskellstuff 你不能只访问talk 的结果,因为它在IO monad 内部。我编辑了问题以参考有关 monad 的良好资源。

以上是关于Haskell websockets 标头的主要内容,如果未能解决你的问题,请参考以下文章

WebSocket JS 的自定义标头

使用Cro :: WebSocket :: Client添加授权或标头?

“发送非空 'Sec-WebSocket-Protocol' 标头但未收到响应” Django 频道

Spring WebSocket:由于升级标头无效,握手失败:null

如何将 HTTP 请求升级到 Websocket (Autobahn & Twisted Web)

如何在 Javascript 中为 websocket 的请求标头设置 cookie?