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

Safe HaskellNone

Network.Simple.TCP

Contents

Description

This module exports functions that abstract simple TCP Socket usage patterns.

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

Server side

The following functions allow you to obtain and use Sockets useful to the server side of a TCP connection.

Here's how you could run a TCP server that handles in different threads each incoming connection to port 8000 at IPv4 address 127.0.0.1:

 listen (Host "127.0.0.1") "8000" $ \(listeningSocket, listeningAddr) -> do
   putStrLn $ "Listening for incoming connections at " ++ show listeningAddr
   forever . acceptFork listeningSocket $ \(connectionSocket, remoteAddr) -> do
     putStrLn $ "Connection established from " ++ show remoteAddr
     -- now you may use connectionSocket as you please within this scope.

If you keep reading you'll discover there are different ways to achieve the same, some ways more general than others. The above one was just an example using a pretty general approach, you are encouraged to use simpler approaches such as serve if those suit your needs.

serveSource

Arguments

:: HostPreference

Preferred host to bind.

-> ServiceName

Service port to bind.

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

Computation to run once an incoming connection is accepted. Takes the connection socket and remote end address.

-> IO r 

Start a TCP server that sequentially accepts and uses each incoming connection.

Both the listening and connection sockets are closed when done or in case of exceptions.

Note: You don't need to use listen nor accept manually if you use this function.

serveForkSource

Arguments

:: HostPreference

Preferred host to bind.

-> ServiceName

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

-> IO () 

Start a TCP server that accepts incoming connections and uses them concurrently in different threads.

The listening and connection sockets are closed when done or in case of exceptions.

Note: You don't need to use listen nor acceptFork manually if you use this function.

Listening

listenSource

Arguments

:: HostPreference

Preferred host to bind.

-> ServiceName

Service port to bind.

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

Computation taking the listening socket and the address it's bound to.

-> IO 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 the listen and sClose functions from Network.Socket instead.

Note: maxListenQueue is tipically 128, which is too small for high performance servers. So, we use the maximum between maxListenQueue and 2048 as the default size of the listening queue. The NoDelay and ReuseAddr options are set on the socket.

Accepting

acceptSource

Arguments

:: Socket

Listening and bound socket.

-> ((Socket, SockAddr) -> IO b)

Computation to run once an incoming connection is accepted. Takes the connection socket and remote end address.

-> IO b 

Accept a single incoming connection and use it.

The connection socket is closed when done or in case of exceptions.

acceptForkSource

Arguments

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

-> IO ThreadId 

Accept a single incoming connection and use it in a different thread.

The connection socket is closed when done or in case of exceptions.

Client side

The following functions allow you to obtain and use Sockets useful to the client side of a TCP connection.

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.

connectSource

Arguments

:: HostName

Server hostname.

-> ServiceName

Server service port.

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

Computation taking the communication socket and the server address.

-> IO r 

Connect to a TCP server and use the connection.

The connection socket is closed when done or in case of exceptions.

If you prefer to acquire and close the socket yourself, then use connectSock and the sClose function from Network.Socket instead.

Low level support

bindSock :: HostPreference -> ServiceName -> IO (Socket, SockAddr)Source

Obtain a Socket bound to the given host name and TCP service port.

The obtained Socket should be closed manually using sClose 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.

connectSock :: HostName -> ServiceName -> IO (Socket, SockAddr)Source

Obtain a Socket connected to the given host and TCP service port.

The obtained Socket should be closed manually using sClose when it's not needed anymore, otherwise you risk having the 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.

Exports

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.

Instances

Eq HostPreference 
Ord HostPreference 
Read HostPreference 
Show HostPreference 
IsString HostPreference

The following special values are recognized: