Asynchronous UDP server/client as base for IPC in Haskell - haskell

I want to put together the basics for asynchronous UDP IPC in Haskell. For this the sender/receiver should issue e.g. an synchronous receive (or send, depending from what side you view it) thread and carry on with other tasks.
This might involve to define a new data type that consists of optional message/data serial numbers and some sort of buffer so that the send thread can stop sending when it gets a notification from the receiver that it cannot cope with the speed.
I aim to make this as light weight & asynchronous as possible.
I have tried a number of things such as starting a new receive thread for every packet (took this approach from a paper about multi player online games), but this was grinding almost everything to a halt.
Below is my innocent first take on this. Any help on e.g. creating buffers, creating serial numbers or a DCCP implementation (that I could not find) in Haskell appreciated. - I would not like to get into opinionated discussions about UDP vs TCP etc..
My snippet stops working once something gets out of sync e.g. when no data arrives any more or when less data arrives than expected. I am looking as said for some way of lightweight (featherweight :D) sync between the send and the receive thread of for an example of such.
main = withSocketsDo $ do
s <- socket AF_INET Datagram defaultProtocol
hostAddr <- inet_addr host
done <- newEmptyMVar
let p = B.pack "ping"
thread <- forkIO $ receiveMessages s done
forM_ [0 .. 10000] $ \i -> do
sendAllTo s (B.pack "ping") (SockAddrInet port hostAddr)
takeMVar done
killThread thread
sClose s
return()
receiveMessages :: Socket -> MVar () -> IO ()
receiveMessages socket done = do
forM_ [0 .. 10000] $ \i -> do
r <- recvFrom socket 1024
print (r) --this is a placeholder to make the fun complete
putMVar done ()

If you don't trust your messenger, you can never agree on anything -- not even a single bit like "are we done yet"!

Related

Can't use multiple clients with Haskell Websocket server

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
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.

Why is chat server example on haskell.org thread safe?

I'm new to Haskell and I can't figure out what I'm not understanding about this example on the Haskell wiki: http://www.haskell.org/haskellwiki/Implement_a_chat_server
The specific code in question is this:
runConn :: (Socket, SockAddr) -> Chan Msg -> -> IO ()
runConn (sock, _) chan = do
let broadcast msg = writeChan chan msg
hdl <- socketToHandle sock ReadWriteMode
hSetBuffering hdl NoBuffering
chan' <- dupChan chan
-- fork off thread for reading from the duplicated channel
forkIO $ fix $ \loop -> do
line <- readChan chan'
hPutStrLn hdl line
loop
-- read lines from socket and echo them back to the user
fix $ \loop -> do
line <- liftM init (hGetLine hdl)
broadcast line
loop
The code above has one thread writing to the handle hdl at the same time (potentially) as another thread is reading from it. Is this safe?
I suspect the nature of forkIO (being internal to Haskell and not a system thread library or process) is what makes this work, but I'm not sure.
I checked the documentation of forkIO for any mention of IO handles
but found nothing. I also checked the documentation of System.IO but couldn't find any mention of using handles between threads without using locking.
So can someone tell me how I should know when something like this is safe when the docs don't mention anything about thread safety?
It's not the nature of forkIO that makes this works but the nature of MVar that is used to implement both Chan and Handle.
If you want to understand how Chan works take a look at this section "MVar as building blocks: Unbounded Channels" in chapter 7 of the excellent book "Parallel and Concurrent Programming in Haskell" by Simon Marlow. In the same chapter there is a section about forkIO and MVar that will help you understand how Handle can be implemented in a thread safe way.
Chapter 12 talks specifically about various ways to implement network servers, including a chat server that is implemented using STM instead of Chans.
If it wasn't safe, blocking sockets would be almost impossible to use. If your protocol is asynchronous and you're using blocking sockets, you need a thread blocking on read pretty much all the time. If you then needed to send a message to the other side, how could you do it? Wait for the other side to send you a message?

Haskell - Slow socket connection when threaded

I've started with Haskell a while ago and now I'm focusing on networking. I followed some
tutorials and source samples to put together a very simple echo server:
main = withSocketsDo $ do
forkIO $ acceptor 8080
print "Server running ... " >> getLine >>= print
tcpSock :: IO Socket
tcpSock = socket AF_INET Stream 0
acceptor :: PortNumber -> IO ()
acceptor port = do
-- Setup server socket
sock <- tcpSock
setSocketOption sock ReuseAddr 1
bindSocket sock (SockAddrInet port iNADDR_ANY)
listen sock 50
-- Start with zero index
loop sock 0
where
loop sock sockId = do
-- Accept socket
(nextSock, addr) <- accept sock
-- Setup the socket for performance
(_, handle) <- setupClient nextSock
-- Run client in own thread
forkIO $ do
-- Get a stream of bytes
stream <- BS.hGetContents handle
-- Echo the first received char
BS.hPut handle $ BS.take 1 stream
-- Kill the socket
SIO.hClose handle
-- Accept next client
loop sock (sockId + 1)
setupClient :: Socket -> IO (Socket, SIO.Handle)
setupClient sock = do
-- Disable nagle
setSocketOption sock NoDelay 1
-- Disable buffering
hdl <- socketToHandle sock SIO.ReadWriteMode
SIO.hSetBuffering hdl SIO.NoBuffering
return (sock, hdl)
Now, I've tested the code with the ab-Tool to benchmark the server. The code is compiled
using -O2 and -threaded and the program is started using +RTS -N to use multiple OS threads.
The code creates a new lightweight thread per client and as far as I remember are these threads
pretty cheap because they are scheduled by a bunch of real OS threads.
After running the tool, the results are:
ab -n 10000 -c 1000 http://localhost:8080/
~ 500 - 1600 req/sec
Yes, it does change sometimes between 500 and 1600!
At first I thought well, not bad. Then I ran the program without "+RTS -N" and results are almost every
time ~20000 req/sec.
Obviously the threading kills the performance pretty badly, but why ?
My guess is, that the IO manager does a pretty bad job when dealing with a lot of connections.
BTW: I use Ubuntu 13.04 and ghc 7.6, but I've tested the code under Windows 8 which gave me far worse results, but I think the IO manager is tuned for linux, which makes sense.
Am I doing something reallly stupid here ?? I know, the example is quite trivial but here is obviously something going wrong.
Regards,
Chris
Okay, I think I semi-solved the problem, though I'm still not sure where the error is/was.
I'm now using the Network package so the accept routine is handle-based. I tried this because I noticed a memory leak after a couple of tests.
This way I solved magially two problem at once, because now the threading makes NO difference.
I really dont know why this is happening, but the handle-based impl. is simpler and obviously faster/more safe.
Maybe this helps other people experiencing the same problem.

Automatically reconnect a Haskell Network connection in an idiomatic way

I've worked my way through Don Stewart's Roll your own IRC bot tutorial, and am playing around with some extensions to it. My current code is essentially the same as the "The monadic, stateful, exception-handling bot in all its glory"; it's a bit too long to paste here unless someone requests it.
Being a Comcast subscriber, it's particularly important that the bot be able to reconnect after periods of poor connectivity. My approach is to simply time the PING requests from the server, and if it goes without seeing a PING for a certain time, to try reconnecting.
So far, the best solution I've found is to wrap the hGetLine in the listen loop with System.Timeout.timeout. However, this seems to require defining a custom exception so that the catch in main can call main again, rather than return (). It also seems quite fragile to specify a timeout value for each individual hGetLine.
Is there a better solution, perhaps something that wraps an IO a like bracket and catch so that the entire main can handle network timeouts without the overhead of a new exception type?
How about running a separate thread that performs all the reading and writing and takes care of periodically reconnecting the handle?
Something like this
input :: Chan Char
output :: Chan Char
putChar c = writeChan output c
keepAlive = forever $ do
h <- connectToServer
catch
(forever $
do c <- readChan output; timeout 4000 (hPutChar h c); return ())
(\_ -> return ())
The idea is to encapsulate all the difficulty with periodically reconnecting into a separate thread.

Haskell concurrency and Handles

I'm writing a little notification server to push data to a client. The basic architecture looks something like this (pared down pseudo-code):
acceptConnections sock = forever $ do
connection <- accept sock
forkIO (handleConnection connection)
handleConnection connection = do
connectionHandle <- socketToHandle connection ReadWriteMode
handleMessage connectionHandle
hClose connectionHandle
handleMessage connectionHandle = forever $ do
message <- hGetLine connectionHandle
if shouldPushMessage message
then hPutStrLn targetConnection message
else return ()
Where targetConnection (in handleMessage) is from a separate connection and is hanging up handleMessage in a different thread waiting for its buffer to be filled. I would think this would cause a problem as I have 2 threads accessing the same Handle. So, my question is, why isn't this a problem? Or is it, and I just haven't seen it turn into an issue yet? In my actual application, when I grab targetConnection, I do so through a map I access via an MVar, but it's not being safely accessed at the hGetLine call.
Disclaimer: I'm a complete Haskell and multi-threaded newb
Thanks for any explanations/insight!
Handle, as implemented in GHC, is already an MVar wrapping over the underlying IODevice. I didn't quite get what you're doing (not saying it was unclear, I'm a little ill so perhaps I'm slow) but am guessing GHCs built in thread-safe handling of Handle is saving you.

Resources