Playing with sockets in Haskell
- Magnus Therning
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
= send s "Ping from child" >> return ()
childFunc s
= do
main <- socketPair AF_UNIX Stream defaultProtocol
(childSock, parentSock) print (childSock, parentSock)
<- forkProcess $ childFunc childSock
child 10 >>= print recv parentSock
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
= do
childFunc sInt let fd = Fd sInt
"Ping from child" >> return ()
fdWrite fd
= do
main <- socketPair AF_UNIX Stream defaultProtocol
(childSock, parentSock) let childInt = fdSocket childSock
print (childInt, parentSock)
<- forkProcess $ childFunc childInt
child 10 >>= print recv parentSock
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
= do
childFunc sInt <- fdToHandle $ Fd sInt
h "Ping from child"
hPutStr h
hFlush h
= do
main <- socketPair AF_UNIX Stream defaultProtocol
(childSock, parentSock) let childInt = fdSocket childSock
print (childSock, parentSock)
<- forkProcess $ childFunc childInt
child 10 >>= print recv parentSock
Let the child take a CInt
and turn it into a Socket
:1
import Control.Concurrent
import Control.Concurrent.MVar
import System.Posix.Process
import System.Posix.IO
import System.Posix.Types
import Network.Socket
= do
childFunc sInt <- mkSocket sInt AF_UNIX Stream defaultProtocol Connected
s "Ping from child" >> return ()
send s
= do
main <- socketPair AF_UNIX Stream defaultProtocol
(childSock, parentSock) let childInt = fdSocket childSock
print (childInt, parentSock)
<- forkProcess $ childFunc childInt
child 10 >>= print recv parentSock
It seems the socket is in the
Connected
state aftersocketPair
succeeds.↩︎