import Network
import System.IO
import Control.Concurrent
import Control.Monad(when)
import Char
serverHandshake :: String
serverHandshake =
"HTTP/1.1 101 Switching Protocols\r\n\
\Upgrade: WebSocket\r\n\
\Connection: Upgrade\r\n\
\Sec-WebSocket-Accept: *******************\r\n\r\n"
acceptLoop socket = forever $ do
(h,_,_) <- accept socket
------------------------
hPutStr h serverHandshake
hSetBuffering h NoBuffering
forkIO (listenLoop h)
where
forever a = do a; forever a
main = withSocketsDo $ do
h <- listenOn (PortNumber 8000)
acceptLoop h
sClose h
return ()
listenLoop :: Handle -> IO ()
listenLoop h = do
sendFrame h "aleloia"
msg <- readFrame h
putStrLn msg
when (msg /= "quit") (listenLoop h)
readFrame :: Handle -> IO String
readFrame h = readUntil h ""
where
readUntil h str = do
new <- hGetChar h
if new == chr 0
then readUntil h ""
else if new == chr 255
then return str
else readUntil h (str ++ [new])
sendFrame :: Handle -> String -> IO ()
sendFrame h s = do
hPutChar h (chr 0)
hPutStr h s
hPutChar h (chr 255)
1)当有“forkIO(listenLoop h)”时,为什么要使用“forever a = do a; forever a” 我读它是永远开始为1个传入连接分配一个新的listenLoop?换句话说,在我的电脑崩溃之前开始分配新流程?如果有一个永远的循环,我希望它在主要的某个地方?
2) - - - 和* * *是一些尚未实现的RFC我在互联网上找不到的东西,有没有用于此的电池?
参考:http://www.fatvat.co.uk/2010/01/web-sockets-and-haskell.html
答案 0 :(得分:2)
据推测accept
是一个阻塞函数调用,因此使用forever
不是一个分叉炸弹。至于为什么你这样做,好吧,我认为这是一个相当标准的做法,一个程序监听套接字接受所需数量的连接。
我不是100%确定是否有“Haskell电池”用于代码的缺失部分,但Hackage上肯定有几个包含名称或描述中的websocket;你应该检查一下然后发一个更具体的问题。
答案 1 :(得分:2)
人们可以在Haskell中编写这样的代码。当你调用forkIO函数时,Haskell使用“绿色线程”,这些线程通常在单个线程中运行,直到它们有理由阻塞,此时它们很可能会使用某种线程池机制来获取阻塞的线程上。此功能加上状态事务monad使得在Haskell中设计并发应用程序变得非常容易。
如果你想使用OS线程,那就是forkOS功能。
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent.html
此外,GHC的Network.Socket模块尽可能使用非阻塞IO功能,所有这些都是对用户隐藏的。