
Jason Dusek
I don't think you want either of the functions you mentioned. What you probably want instead is to do concurrent programming by creating Haskell threads. A hundred Haskell threads reading from Handles are translated to one or more OS threads using whatever polling mechanism (select(), poll(), epoll) your operating system supports.
I have uploaded a simple concurrent echo server implementation to hpaste [1]. It uses one thread for the stdout logger, one thread for the server, one thread for each client and finally a main thread waiting for you to hit enter to quit the application.
[1] http://hpaste.org/52742 - Concurrent echo server with logger
I am not sure how to apply the principle you mention to a proxy, which must read from and write to both handles in turn (or, ideally, as needed).
A proxy server acts a lot like an echo server. The difference is that usually before the actual proxying starts you have a negotiation phase, and instead of echoing back to the same socket, you just write it to a different one. Here is an (untested) example: (clientH, clientHost, clientPort) <- accept serverSock destH <- negotiate clientH doneVar <- newEmptyMVar forkIO (hGetContents clientH >>= hPutStr destH >>= putMVar doneVar) forkIO (hGetContents destH >>= hPutStr clientH >>= putMVar doneVar) replicateM_ 2 (takeMVar doneVar) mapM_ hClose [clientH, destH] Of course this code is going to bite you in production for two reasons: First of all it has no error handling. If the 'negotiate' function throws an exception, then nobody will close the client handle. So view this is a highly simplified example! The second reason is that in this lazy I/O framework it is extraordinarily difficult to write the 'negotiate' function in the first place, unless you allow yourself to put stuff back into the handle or process only one byte at a time. Both options are bad. A better option is to use a proper I/O abstraction suitable for protocol processing. Iteratees [1] come to mind. They solve this problem elegantly and let you really just use the parser style "destH <- negotiate". My usage of the MVar is actually kind of an abuse. I just use it to allow the two forwarder threads to signal their completion. The main thread just waits for the two to complete and then closes both handles. The word "abuse" is perhaps too strong, because there is essentially nothing wrong with the approach. The standard concurrency library doesn't provide an event primitive, so the more general MVar is often used for this. [1] http://www.yesodweb.com/book/enumerator Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/