Safe Haskell | None |
---|---|
Language | Haskell98 |
This module exports functions that abstract simple TCP Socket
usage patterns.
This module uses MonadIO
and MonadMask
extensively so that you can
reuse these functions in monads other than IO
. However, if you don't care
about any of that, just pretend you are using the IO
monad all the time
and everything will work as expected.
Synopsis
- connect :: (MonadIO m, MonadMask m) => HostName -> ServiceName -> ((Socket, SockAddr) -> m r) -> m r
- connectSOCKS5 :: (MonadIO m, MonadMask m) => HostName -> ServiceName -> HostName -> ServiceName -> ((Socket, SockAddr, SockAddr) -> m r) -> m r
- serve :: MonadIO m => HostPreference -> ServiceName -> ((Socket, SockAddr) -> IO ()) -> m a
- listen :: (MonadIO m, MonadMask m) => HostPreference -> ServiceName -> ((Socket, SockAddr) -> m r) -> m r
- accept :: (MonadIO m, MonadMask m) => Socket -> ((Socket, SockAddr) -> m r) -> m r
- acceptFork :: MonadIO m => Socket -> ((Socket, SockAddr) -> IO ()) -> m ThreadId
- recv :: MonadIO m => Socket -> Int -> m (Maybe ByteString)
- send :: MonadIO m => Socket -> ByteString -> m ()
- sendLazy :: MonadIO m => Socket -> ByteString -> m ()
- sendMany :: MonadIO m => Socket -> [ByteString] -> m ()
- bindSock :: MonadIO m => HostPreference -> ServiceName -> m (Socket, SockAddr)
- listenSock :: MonadIO m => Socket -> Int -> m ()
- connectSock :: MonadIO m => HostName -> ServiceName -> m (Socket, SockAddr)
- connectSockSOCKS5 :: MonadIO m => Socket -> HostName -> ServiceName -> m SockAddr
- closeSock :: MonadIO m => Socket -> m ()
- withSocketsDo :: IO a -> IO a
- data HostPreference
- type HostName = String
- type ServiceName = String
- data Socket
- data SockAddr
Introduction to TCP networking
This introduction aims to give you a overly simplified overview of some concepts you need to know about TCP sockets in order to make effective use of this module.
There are two ends in a single TCP connection: one is the TCP «server» and the other is the TCP «client». Each end is uniquely identified by an IP address and a TCP port pair, and each end knows the IP address and TCP port of the other end. Each end can send and receive data to and from the other end.
A TCP server, once «bound» to a well-known IP address and TCP port, starts «listening» for incoming connections from TCP clients to such bound IP address and TCP port. When a TCP client attempts to connect to the TCP server, the TCP server must «accept» the incoming connection in order to start exchanging data with the remote end. A single TCP server can sequentially accept many incoming connections, possibly handling each one concurrently.
A TCP client can «connect» to a well-known IP address and TCP port previously bound by a listening TCP server willing to accept new incoming connections. Once the connection is established, the TCP client can immediately start exchanging data with the TCP server. The TCP client is randomly assigned a TCP port when connecting, and its IP address is selected by the operating system so that it is reachable from the remote end.
The TCP client a and the TCP server can be running in the same host or in different hosts.
Client side
Here's how you could run a TCP client:
connect
"www.example.org" "80" $ \(connectionSocket, remoteAddr) -> do putStrLn $ "Connection established to " ++ show remoteAddr -- Now you may use connectionSocket as you please within this scope, -- possibly usingrecv
andsend
to interact with the remote end.
:: (MonadIO m, MonadMask m) | |
=> HostName | Server hostname or IP address. |
-> ServiceName | Server service port name or number. |
-> ((Socket, SockAddr) -> m r) | Computation taking the communication socket and the server address. |
-> m r |
Connect to a TCP server and use the connection.
The connection socket is shut down and closed when done or in case of exceptions.
If you prefer to acquire and close the socket yourself, then use
connectSock
and closeSock
.
Note: The NoDelay
and KeepAlive
options are set on the socket.
:: (MonadIO m, MonadMask m) | |
=> HostName | SOCKS5 proxy server hostname or IP address. |
-> ServiceName | SOCKS5 proxy server service port name or number. |
-> HostName | Destination server hostname or IP address. We connect to this host through the SOCKS5 proxy specified in the previous arguments. Note that if hostname resolution on this |
-> ServiceName | Destination server service port name or number. |
-> ((Socket, SockAddr, SockAddr) -> m r) | Computation taking |
-> m r |
Like connect
, but connects to the destination server through a SOCKS5
proxy.
Server side
Here's how you can run a TCP server that handles in different threads each
incoming connection to port 8000
at IPv4 address 127.0.0.1
:
serve
(Host
"127.0.0.1") "8000" $ \(connectionSocket, remoteAddr) -> do putStrLn $ "TCP connection established from " ++ show remoteAddr -- Now you may use connectionSocket as you please within this scope, -- possibly usingrecv
andsend
to interact with the remote end.
If you need more control on the way your server runs, then you can use more
advanced functions such as listen
, accept
and acceptFork
.
:: MonadIO m | |
=> HostPreference | Host to bind. |
-> ServiceName | Server service port name or number to bind. |
-> ((Socket, SockAddr) -> IO ()) | Computation to run in a different thread once an incoming connection is accepted. Takes the connection socket and remote end address. |
-> m a | This function never returns. |
Start a TCP server that accepts incoming connections and handles them concurrently in different threads.
Any acquired sockets are properly shut down and closed when done or in case
of exceptions. Exceptions from the threads handling the individual
connections won't cause serve
to die.
Note: This function performs listen
, acceptFork
, so don't perform
those manually.
Listening
:: (MonadIO m, MonadMask m) | |
=> HostPreference | Host to bind. |
-> ServiceName | Server service port name or number to bind. |
-> ((Socket, SockAddr) -> m r) | Computation taking the listening socket and the address it's bound to. |
-> m r |
Bind a TCP listening socket and use it.
The listening socket is closed when done or in case of exceptions.
If you prefer to acquire and close the socket yourself, then use bindSock
and closeSock
, as well as listenSock
function.
Note: The NoDelay
, KeepAlive
and ReuseAddr
options are set on
the socket. The maximum number of incoming queued connections is 2048.
Accepting
:: (MonadIO m, MonadMask m) | |
=> Socket | Listening and bound socket. |
-> ((Socket, SockAddr) -> m r) | Computation to run once an incoming connection is accepted. Takes the connection socket and remote end address. |
-> m r |
Accept a single incoming connection and use it.
The connection socket is shut down and closed when done or in case of exceptions.
:: MonadIO m | |
=> Socket | Listening and bound socket. |
-> ((Socket, SockAddr) -> IO ()) | Computation to run in a different thread once an incoming connection is accepted. Takes the connection socket and remote end address. |
-> m ThreadId |
Accept a single incoming connection and use it in a different thread.
The connection socket is shut down and closed when done or in case of exceptions.
Utils
send :: MonadIO m => Socket -> ByteString -> m () Source #
Writes a ByteString
to the socket.
Note: On POSIX, calling sendLazy
once is much more efficient than
repeatedly calling send
on strict ByteString
s. Use
if you have more than one strict sendLazy
sock .
fromChunks
ByteString
to send.
sendLazy :: MonadIO m => Socket -> ByteString -> m () Source #
Writes a lazy ByteString
to the socket.
Note: This uses writev(2)
on POSIX.
sendMany :: MonadIO m => Socket -> [ByteString] -> m () Source #
Deprecated: Use sendLazy
sock . fromChunks
Writes the given list of ByteString
s to the socket.
Note: This uses writev(2)
on POSIX.
Low level support
:: MonadIO m | |
=> HostPreference | Host to bind. |
-> ServiceName | Server service port name or number to bind. |
-> m (Socket, SockAddr) | Bound socket and address. |
Obtain a Socket
bound to the given host name and TCP service port.
The obtained Socket
should be closed manually using closeSock
when
it's not needed anymore.
Prefer to use listen
if you will be listening on this socket and using it
within a limited scope, and would like it to be closed immediately after its
usage or in case of exceptions.
Note: The NoDelay
, KeepAlive
and ReuseAddr
options are set on
the socket.
:: MonadIO m | |
=> Socket | Bound socket. |
-> Int | Maximum number of incoming queued connections (we suggest |
-> m () |
Listen for new connections of the given bound socket.
:: MonadIO m | |
=> HostName | Server hostname or IP address. |
-> ServiceName | Server service port name or number. |
-> m (Socket, SockAddr) | Connected socket and server address. |
Obtain a Socket
connected to the given host and TCP service port.
The obtained Socket
should be closed manually using closeSock
when
it's not needed anymore, otherwise you risk having the connection and socket
open for much longer than needed.
Prefer to use connect
if you will be using the socket within a limited
scope and would like it to be closed immediately after its usage or in case
of exceptions.
Note: The NoDelay
and KeepAlive
options are set on the socket.
:: MonadIO m | |
=> Socket | Socket connected to the SOCKS5 proxy server. After a successful use of |
-> HostName | Destination server hostname or IP address. We connect to this host through the SOCKS5 proxy specified in the previous arguments. Note that if hostname resolution on this |
-> ServiceName | Destination server service port name or number. |
-> m SockAddr | Address of the destination server. |
Given a Socket
connected to a SOCKS5 proxy server, establish a
connection to the specified destination server through that proxy.
closeSock :: MonadIO m => Socket -> m () Source #
Shuts down and closes the Socket
, silently ignoring any synchronous
exception that might happen.
Note to Windows users
withSocketsDo :: IO a -> IO a #
With older versions of the network
library (version 2.6.0.2 or earlier)
on Windows operating systems,
the networking subsystem must be initialised using withSocketsDo
before
any networking operations can be used. eg.
main = withSocketsDo $ do {...}
It is fine to nest calls to withSocketsDo
, and to perform networking operations
after withSocketsDo
has returned.
In newer versions of the network
library (version v2.6.1.0 or later)
it is only necessary to call
withSocketsDo
if you are calling the MkSocket
constructor directly.
However, for compatibility with older versions on Windows, it is good practice
to always call withSocketsDo
(it's very cheap).
Types
data HostPreference Source #
Preferred host to bind.
HostAny | Any available host. |
HostIPv4 | Any available IPv4 host. |
HostIPv6 | Any available IPv6 host. |
Host HostName | An explicit host name. |
Instances
Re-exported from Network.Socket
Either a host name e.g., "haskell.org"
or a numeric host
address string consisting of a dotted decimal IPv4 address or an
IPv6 address e.g., "192.168.0.1"
.
type ServiceName = String #
A socket data type.
Socket
s are not GCed unless they are closed by close
.
The existence of a constructor does not necessarily imply that
that socket address type is supported on your system: see
isSupportedSockAddr
.
Instances
Eq SockAddr | |
Ord SockAddr | |
Defined in Network.Socket.Types |