Gert Cuykens
Gert Cuykens

Reputation: 7155

haskell websocket example

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

Answers (2)

Ant
Ant

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

Daniel Wagner
Daniel Wagner

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

Related Questions