|
31 | 31 | -- > import Network.Socket.ByteString (recv, sendAll)
|
32 | 32 | -- >
|
33 | 33 | -- > main :: IO ()
|
34 |
| --- > main = withSocketsDo $ do |
35 |
| --- > addr <- resolve "3000" |
| 34 | +-- > main = runTCPServer Nothing "3000" talk |
| 35 | +-- > where |
| 36 | +-- > talk s = do |
| 37 | +-- > msg <- recv s 1024 |
| 38 | +-- > unless (S.null msg) $ do |
| 39 | +-- > sendAll s msg |
| 40 | +-- > talk s |
| 41 | +-- > |
| 42 | +-- > runTCPServer :: Maybe HostName -> ServiceName -> (Socket -> IO a) -> IO a |
| 43 | +-- > runTCPServer mhost port server = withSocketsDo $ do |
| 44 | +-- > addr <- resolve |
36 | 45 | -- > E.bracket (open addr) close loop
|
37 | 46 | -- > where
|
38 |
| --- > resolve port = do |
| 47 | +-- > resolve = do |
39 | 48 | -- > let hints = defaultHints {
|
40 | 49 | -- > addrFlags = [AI_PASSIVE]
|
41 | 50 | -- > , addrSocketType = Stream
|
42 | 51 | -- > }
|
43 |
| --- > addr:_ <- getAddrInfo (Just hints) Nothing (Just port) |
44 |
| --- > return addr |
| 52 | +-- > head <$> getAddrInfo (Just hints) mhost (Just port) |
45 | 53 | -- > open addr = do
|
46 | 54 | -- > sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
|
47 | 55 | -- > setSocketOption sock ReuseAddr 1
|
48 |
| --- > -- If the prefork technique is not used, |
49 |
| --- > -- set CloseOnExec for the security reasons. |
50 | 56 | -- > withFdSocket sock $ setCloseOnExecIfNeeded
|
51 |
| --- > bind sock (addrAddress addr) |
52 |
| --- > listen sock 10 |
| 57 | +-- > bind sock $ addrAddress addr |
| 58 | +-- > listen sock 1024 |
53 | 59 | -- > return sock
|
54 | 60 | -- > loop sock = forever $ do
|
55 |
| --- > (conn, peer) <- accept sock |
56 |
| --- > putStrLn $ "Connection from " ++ show peer |
57 |
| --- > void $ forkFinally (talk conn) (\_ -> close conn) |
58 |
| --- > talk conn = do |
59 |
| --- > msg <- recv conn 1024 |
60 |
| --- > unless (S.null msg) $ do |
61 |
| --- > sendAll conn msg |
62 |
| --- > talk conn |
| 61 | +-- > (conn, _peer) <- accept sock |
| 62 | +-- > void $ forkFinally (server conn) (const $ gracefulClose conn 5000) |
63 | 63 | --
|
64 | 64 | -- > {-# LANGUAGE OverloadedStrings #-}
|
65 | 65 | -- > -- Echo client program
|
|
71 | 71 | -- > import Network.Socket.ByteString (recv, sendAll)
|
72 | 72 | -- >
|
73 | 73 | -- > main :: IO ()
|
74 |
| --- > main = withSocketsDo $ do |
75 |
| --- > addr <- resolve "127.0.0.1" "3000" |
76 |
| --- > E.bracket (open addr) close talk |
| 74 | +-- > main = runTCPClient "127.0.0.1" "3000" $ \s -> do |
| 75 | +-- > sendAll s "Hello, world!" |
| 76 | +-- > msg <- recv s 1024 |
| 77 | +-- > putStr "Received: " |
| 78 | +-- > C.putStrLn msg |
| 79 | +-- > |
| 80 | +-- > runTCPClient :: HostName -> ServiceName -> (Socket -> IO a) -> IO a |
| 81 | +-- > runTCPClient host port client = withSocketsDo $ do |
| 82 | +-- > addr <- resolve |
| 83 | +-- > E.bracket (open addr) close client |
77 | 84 | -- > where
|
78 |
| --- > resolve host port = do |
| 85 | +-- > resolve = do |
79 | 86 | -- > let hints = defaultHints { addrSocketType = Stream }
|
80 |
| --- > addr:_ <- getAddrInfo (Just hints) (Just host) (Just port) |
81 |
| --- > return addr |
| 87 | +-- > head <$> getAddrInfo (Just hints) (Just host) (Just port) |
82 | 88 | -- > open addr = do
|
83 | 89 | -- > sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
|
84 | 90 | -- > connect sock $ addrAddress addr
|
85 | 91 | -- > return sock
|
86 |
| --- > talk sock = do |
87 |
| --- > sendAll sock "Hello, world!" |
88 |
| --- > msg <- recv sock 1024 |
89 |
| --- > putStr "Received: " |
90 |
| --- > C.putStrLn msg |
91 | 92 | --
|
92 | 93 | -- The proper programming model is that one 'Socket' is handled by
|
93 | 94 | -- a single thread. If multiple threads use one 'Socket' concurrently,
|
|
0 commit comments