Reputation: 2037
I have played a bit with the Network library, the "simple" form where the use is fairly easy: a combination of 'listenOn', 'connectTo', 'accept' and we have something working. Now I am trying to use the "real" thing, meaning Network.Socket and Network.Socket.ByteString because I'd like to send files between a client and a server. But it is not as easy to use as the higher level interface and I'm looking for some code examples and/or how-tos. Particularly, the code dealing with 'getAddrInfo', 'AddrInfo' and 'SockAddr' I don't understand very deeply.
So, where can I get this type of resource?
Upvotes: 1
Views: 364
Reputation: 4283
I can just show an own example:
import Network.Socket
( SocketType(..), AddrInfo(..), AddrInfoFlag(..), Family(..), socket, sClose,
defaultHints, withSocketsDo, connect, getAddrInfo, defaultProtocol )
import Network.Socket.ByteString( sendAll, recv )
import qualified Data.ByteString.Char8 as BC( readFile, hPut, null )
sendFile :: String -> Int -> FilePath -> IO Bool
sendFile server port filename = withSocketsDo $ do
addrinfos <- getAddrInfo desiredAddr (Just server) (Just . show $ port)
if null addrinfos
then do
return False
else do
datafile <- BC.readFile filename
let serveraddr = head addrinfos
sock <- socket (addrFamily serveraddr) Stream defaultProtocol
connect sock (addrAddress serveraddr)
sendAll sock datafile
sClose sock
return True
I don't test (just cut from my code file) so maybe fails in the imports. On the server I use:
readerThread :: MyQueue -> Socket -> IO ()
readerThread queue serverSock = do
(connsock, clientaddr) <- accept serverSock
sClose serverSock
putStrLn $ "> connected reader " ++ show clientaddr
talk connsock
sClose connsock
putStrLn $ "> closed reader " ++ show clientaddr
return ()
where
talk conn = do
msg <- recv conn 2048
putStr $ "* get from " ++ show conn ++ "\n"
myQueueWrite queue msg
unless (B.null msg) $ do
talk conn
createInputPort :: ChildLocks -> MyQueue -> AddrInfo -> IO PortNumber
createInputPort children obuffer serverAddr = withSocketsDo $ do
serverSock <- socket AF_INET Stream defaultProtocol
bindSocket serverSock (addrAddress serverAddr)
listen serverSock 1
lock <- newChildLock children
_ <- forkIO $ readerThread obuffer serverSock `finally` endChildLock lock
socketPort serverSock
Y use a own queue (TCHAN) to comunicate between network reader an consumer thread, and childLocks to wait at the end with something like waitForChildren children
construct that I found on stackoverflow.
UPDATE: the waitForChildren
is on post Comparing Haskell threads to kernel threads - is my benchmark viable?
Upvotes: 1
Reputation: 64740
The .Socket
interface is little more than bindings to berkeley sockets, I suggest you read Beej's guide to network programming (for C) to get a handle on this.
EDIT: The pharse "little more than" isn't intended to slight the amount of work that goes into making this layer configure, build, and install smoothly on all the supported platforms. I'm just saying there's basically a one-to-one relation between many of the .Socket operations and the man (3) pages for the C primitives.
Upvotes: 1
Reputation: 9009
There's an example at the bottom of the documentation for the Network.Socket.ByteString
module.
Upvotes: 1