Can't use multiple clients with Haskell Websocket server

Viewed 150

I am trying to test my game server with websockets, but i am having problems using multiple clients. Connecting every single one of them works fine, but when i start the game and send the first messages over the sockets they throw an "ConnectionClosed" error.

The server code looks like this:

main :: IO ()
main = do
    state <- newMVar []
    putStrLn "listening"
    WS.runServer "127.0.0.1" 9000 $ \pen -> do
        c <- WS.acceptRequest pen
        putStrLn "user connected"
        cs <- takeMVar state
        let cs' = c : cs
        case Vector.fromList cs' :: Maybe (Vector.Vector 4 WS.Connection) of
            Just v -> do
                let
                    us = Vector.imap
                        (\i x -> websocketUser x ("websocket user " ++ show i))
                        v
                putMVar state []
                g <- exampleGame us
                _ <- playGame g
                return ()
            Nothing -> putMVar state cs'

To test this I opened 4 chrome tabs and connected each one of them to the server. For every tab i connect the server prints the "user connected" line and after 4 connections the game should start but all sockets get disconnected. It does work fine if I only connect one client. So I think the problem is that I am connection all clients from the same machine. However I don't know how I can test this without using multiple devices. I already tried using different browsers and ports for each client.

My question: Is this caused by connecting all clients from the same machine and chrome or the server reuses the existing connections or something similar, if yes how can I solve this so I can test my game localy? Or is there something wrong with my Haskell code?

websocket library

vector-sized

1 Answers

See the documentation for the ServerApp type. Once the IO action finishes, the underlying socket is closed. So, each of your first three clients accepts a connection, stores the connection in the state, and then finishes, closing the connection. Only the fourth client keeps its connection open, and it can't do anything useful with the other three connections, which have now been closed.

If you replace the last line with:

Nothing -> do
    putMVar state cs'
    threadDelay (10^9)  -- wait a while

then that will probably get all four clients connected.

To fix this "for real", you could have the first three connections wait forever and then arrange for the fourth thread to kill them when the game is over.

However, I'm not sure this is the right architecture. Instead of having the only the fourth connection thread running and polling all four connections, you probably want each connection thread to enter a loop to process incoming messages from its client. These threads can modify a shared game state and/or directly broadcast messages to the other client (like the sample "chat" program in the websockets documentation) or else queue up incoming messages for a separate game thread to process.

Related