Playing with sockets in Haskell
This is another one of those posts that I make mostly for myself, you know for
organising and help my memory
There are as far as I can see three ways to deal with sockets in Haskell.
There’s the type Socket which is used throughout Network.Socket. From
that it’s possible to get to the underlying filedescriptor, and it in turn can
be converted to a Handle.
When coupled with fork+exec it’s crucial to make sure the child process can
find the socket Leaving it in a predictable place seems to be the easiest way
to do that, and as far as I can see that requires using dupTo from
System.Posix.IO. So, on the child-side it’s necessary to find a way to turn
an integer (CInt) into something that can be treated as a socket (i.e. a
Socket, a Handle, or a filedescriptor).
A basic parent-child which obviously won’t work since the child’s socket is
represented as a Socket:
import Control.Concurrent import System.Posix.Process import Network.Socket childFunc s = send s "Ping from child" >> return () main = do (childSock, parentSock) <- socketPair AF_UNIX Stream defaultProtocol print (childSock, parentSock) child <- forkProcess $ childFunc childSock recv parentSock 10 >>= print |
Let the child take a CInt and turn it into a filedescriptor:
import Control.Concurrent import Control.Concurrent.MVar import System.Posix.Process import System.Posix.IO import System.Posix.Types import Network.Socket childFunc sInt = do let fd = Fd sInt fdWrite fd "Ping from child" >> return () main = do (childSock, parentSock) <- socketPair AF_UNIX Stream defaultProtocol let childInt = fdSocket childSock print (childInt, parentSock) child <- forkProcess $ childFunc childInt recv parentSock 10 >>= print |
Let the child take a CInt and turn it into a Handle:
import Control.Concurrent import System.Posix.Process import System.Posix.IO import System.Posix.Types import Network.Socket import System.IO childFunc sInt = do h <- fdToHandle $ Fd sInt hPutStr h "Ping from child" hFlush h main = do (childSock, parentSock) <- socketPair AF_UNIX Stream defaultProtocol let childInt = fdSocket childSock print (childSock, parentSock) child <- forkProcess $ childFunc childInt recv parentSock 10 >>= print |
Let the child take a CInt and turn it into a Socketi:
import Control.Concurrent import Control.Concurrent.MVar import System.Posix.Process import System.Posix.IO import System.Posix.Types import Network.Socket childFunc sInt = do s <- mkSocket sInt AF_UNIX Stream defaultProtocol Connected send s "Ping from child" >> return () main = do (childSock, parentSock) <- socketPair AF_UNIX Stream defaultProtocol let childInt = fdSocket childSock print (childInt, parentSock) child <- forkProcess $ childFunc childInt recv parentSock 10 >>= print |
- It seems the socket
is in the
Connectedstate aftersocketPairsucceeds.[back]