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