Reputation: 7155
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) why use "forever a = do a; forever a" when there is "forkIO (listenLoop h)" I read it as forever start forking a new listenLoop for 1 incoming connection? In other words start forking new processes until my pc crashes? If there would be a forever loop I expect it to be in the main somewhere?
2) - - - and * * * is some not yet implemented RFC stuff I could not find on the internet, are there haskell batteries for this?
ref: http://www.fatvat.co.uk/2010/01/web-sockets-and-haskell.html
Upvotes: 1
Views: 1189
Reputation: 21
There's a reason people can write code like this in Haskell. Haskell uses a "green thread" when you call the forkIO function, these threads generally run in a single thread until they have a reason to block, at which point they will most likely use some kind of thread pooling mechanism to obtain a thread to block on. This feature plus the state transaction monad makes designing concurrent applications in Haskell stupidly easy.
If you want to use OS threads there's the forkOS function.
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent.html
Additionally, the Network.Socket module for GHC uses non-blocking IO functions whenever it can, all of this is hidden from the user.
Upvotes: 2
Reputation: 152837
Presumably accept
is a blocking function call, so the use of forever
isn't a fork-bomb. As for why you do this, well, I think it's fairly standard practice for a program that listens on a socket to accept as many connections as are requested of it.
I'm not 100% sure whether there are "Haskell batteries" for exactly the missing parts of your code, but there are definitely several packages on Hackage with websocket in their name or description; you should check those out and then post a more specific question.
Upvotes: 2