on 4e34693 help sign in
169 lines 5.5 kB history raw
1-- |
2-- Module : Streamly.Network.Socket
3-- Copyright : (c) 2018 Composewell Technologies
4--
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : released
8-- Portability : GHC
9--
10-- This module provides socket based streaming APIs to to receive connections
11-- from remote hosts, and to read and write from and to network sockets.
12--
13-- For basic socket types and operations please consult the @Network.Socket@
14-- module of the <http://hackage.haskell.org/package/network network> package.
15--
16-- = Examples
17--
18-- To write a server, use the 'acceptor' unfold to start listening for
19-- connections from clients. 'acceptor' generates a stream of connected
20-- sockets. We can map an effectful action on this socket stream to handle the
21-- connections. The action would typically use socket reading and writing
22-- operations to communicate with the remote host. We can read/write a stream
23-- of bytes or a stream of chunks of bytes ('Array').
24--
25-- Following is a short example of a concurrent echo server. Please note that
26-- this example can be written even more succinctly by using higher level
27-- operations from "Streamly.Network.Inet.TCP" module.
28--
29-- >>> :set -XFlexibleContexts
30-- >>>
31-- >>> import Data.Function ((&))
32-- >>> import Network.Socket
33-- >>> import Streamly.Network.Socket (SockSpec(..))
34-- >>>
35-- >>> import qualified Streamly.Data.Fold as Fold
36-- >>> import qualified Streamly.Data.Stream as Stream
37-- >>> import qualified Streamly.Data.Stream.Prelude as Stream
38-- >>> import qualified Streamly.Network.Socket as Socket
39-- >>>
40-- >>> :{
41-- main :: IO ()
42-- main = do
43-- let spec = SockSpec
44-- { sockFamily = AF_INET
45-- , sockType = Stream
46-- , sockProto = defaultProtocol
47-- , sockOpts = []
48-- }
49-- addr = SockAddrInet 8090 (tupleToHostAddress (0,0,0,0))
50-- in server spec addr
51-- where
52-- server spec addr =
53-- Stream.unfold Socket.acceptor (maxListenQueue, spec, addr)
54-- & Stream.parMapM (Stream.eager True) (Socket.forSocketM echo)
55-- & Stream.fold Fold.drain
56-- echo sk =
57-- Stream.unfold Socket.chunkReader sk -- Stream IO (Array Word8)
58-- & Stream.fold (Socket.writeChunks sk) -- IO ()
59-- :}
60--
61-- = Programmer Notes
62--
63-- Read IO requests to connected stream sockets are performed in chunks of
64-- 'Streamly.Internal.Data.Array.Type.defaultChunkSize'. Unless
65-- specified otherwise in the API, writes are collected into chunks of
66-- 'Streamly.Internal.System.IO.defaultChunkSize' before they are written to
67-- the socket.
68--
69-- >>> import qualified Streamly.Network.Socket as Socket
70--
71-- = See Also
72--
73-- * "Streamly.Internal.Network.Socket"
74-- * <http://hackage.haskell.org/package/network network>
76-------------------------------------------------------------------------------
77-- Internal Notes
78-------------------------------------------------------------------------------
79--
80-- A socket is a handle to a protocol endpoint.
81--
82-- This module provides APIs to read and write streams and arrays from and to
83-- network sockets. Sockets may be connected or unconnected. Connected sockets
84-- can only send or recv data to/from the connected endpoint, therefore, APIs
85-- for connected sockets do not need to explicitly specify the remote endpoint.
86-- APIs for unconnected sockets need to explicitly specify the remote endpoint.
87--
88-- By design, connected socket IO APIs are similar to
89-- "Streamly.Data.Array.Foreign" read write APIs. They are almost identical to the
90-- sequential streaming APIs in "Streamly.Internal.FileSystem.File".
91--
92module Streamly.Network.Socket
93 (
94 -- * Socket Specification
95 SockSpec(..)
97 -- * Accept Connections
98 , acceptor
100 -- * Reads
101 -- ** Singleton
102 , getChunk
104 -- ** Unfolds
105 , reader
106 , readerWith
107 , chunkReader
108 , chunkReaderWith
110 -- * Writes
111 -- ** Singleton
112 , putChunk
114 -- ** Folds
115 , write
116 , writeWith
117 , writeChunks
118 , writeChunksWith
120 -- * Exceptions
121 , forSocketM
123 -- * Deprecated
124 , accept
125 , readChunk
126 , writeChunk
127 , read
128 , readWithBufferOf
129 , readChunks
130 , readChunksWithBufferOf
131 , writeWithBufferOf
132 , writeChunksWithBufferOf
133 )
134where
136import Control.Monad.IO.Class (MonadIO(..))
137import Data.Word (Word8)
138import Network.Socket (Socket, SockAddr)
139import Streamly.Internal.Data.Unfold (Unfold(..))
140import Streamly.Internal.Data.Array (Array(..))
141import Streamly.Internal.Data.Unbox (Unbox)
143import Streamly.Internal.Network.Socket hiding (accept, read, readChunks)
144import Prelude hiding (read)
146{-# DEPRECATED accept "Please use 'acceptor' instead" #-}
147{-# INLINE accept #-}
148accept :: MonadIO m => Unfold m (Int, SockSpec, SockAddr) Socket
149accept = acceptor
151{-# DEPRECATED readChunk "Please use 'getChunk' instead" #-}
152{-# INLINABLE readChunk #-}
153readChunk :: Int -> Socket -> IO (Array Word8)
154readChunk = getChunk
156{-# DEPRECATED writeChunk "Please use 'putChunk' instead" #-}
157{-# INLINABLE writeChunk #-}
158writeChunk :: Unbox a => Socket -> Array a -> IO ()
159writeChunk = putChunk
161{-# DEPRECATED read "Please use 'reader' instead" #-}
162{-# INLINE read #-}
163read :: MonadIO m => Unfold m Socket Word8
164read = reader
166{-# DEPRECATED readChunks "Please use 'chunkReader' instead" #-}
167{-# INLINE readChunks #-}
168readChunks :: MonadIO m => Unfold m Socket (Array Word8)
169readChunks = chunkReader