network-simple-0.4.5: Simple network sockets usage patterns.

Safe HaskellNone
LanguageHaskell98

Network.Simple.TCP

Contents

Description

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

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 using recv and send to interact with the remote end.

connect Source #

Arguments

:: (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.

connectSOCKS5 Source #

Arguments

:: (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 HostName is necessary, it will happen on the proxy side for security reasons, not locally.

-> ServiceName

Destination server service port name or number.

-> ((Socket, SockAddr, SockAddr) -> m r)

Computation taking Socket connected to the SOCKS5 server (through which we can interact with the destination server), the address of that SOCKS5 server, and the address of the destination server, in that order.

-> 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 using recv and send 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.

serve Source #

Arguments

:: 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

listen Source #

Arguments

:: (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

accept Source #

Arguments

:: (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.

acceptFork Source #

Arguments

:: 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

recv :: MonadIO m => Socket -> Int -> m (Maybe ByteString) Source #

Read up to a limited number of bytes from a socket.

Returns Nothing if the remote end closed the connection or end-of-input was reached. The number of returned bytes might be less than the specified limit, but it will never null.

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 ByteStrings. Use sendLazy sock . fromChunks if you have more than one strict 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 ByteStrings to the socket.

Note: This uses writev(2) on POSIX.

Low level support

bindSock Source #

Arguments

:: 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.

listenSock Source #

Arguments

:: MonadIO m 
=> Socket

Bound socket.

-> Int

Maximum number of incoming queued connections (we suggest 2048 if you don't have an opinion).

-> m () 

Listen for new connections of the given bound socket.

connectSock Source #

Arguments

:: 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.

connectSockSOCKS5 Source #

Arguments

:: MonadIO m 
=> Socket

Socket connected to the SOCKS5 proxy server.

After a successful use of connectSockSOCKS5, all traffic exchanged through this socket will be between ourselves and the destination server.

-> 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 HostName is necessary, it will happen on the proxy side for security reasons, not locally.

-> 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.

withSocketsDo is not necessary for the current network library. 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.

Constructors

HostAny

Any available host.

HostIPv4

Any available IPv4 host.

HostIPv6

Any available IPv6 host.

Host HostName

An explicit host name.

Re-exported from Network.Socket

type HostName = String #

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 #

Either a service name e.g., "http" or a numeric port number.

data Socket #

Basic type for a socket.

Instances
Eq Socket 
Instance details

Defined in Network.Socket.Types

Methods

(==) :: Socket -> Socket -> Bool #

(/=) :: Socket -> Socket -> Bool #

Show Socket 
Instance details

Defined in Network.Socket.Types

data SockAddr #

Socket addresses. The existence of a constructor does not necessarily imply that that socket address type is supported on your system: see isSupportedSockAddr.

Instances
Eq SockAddr 
Instance details

Defined in Network.Socket.Types

Ord SockAddr 
Instance details

Defined in Network.Socket.Types

NFData SockAddr 
Instance details

Defined in Network.Socket.Types

Methods

rnf :: SockAddr -> () #

SocketAddress SockAddr 
Instance details

Defined in Network.Socket.Types