The proper programming model is that one Socket is handled by
a single thread. If multiple threads use one Socket concurrently,
unexpected things would happen. There is one exception for multiple
threads vs a single Socket: one thread reads data from a Socket
only and the other thread writes data to the Socket only.

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.

Resolve a host or service name to one or more addresses.
The AddrInfo values that this function returns contain SockAddr
values that you can pass directly to connect or
bind.

This function is protocol independent. It can return both IPv4 and
IPv6 address information.

The AddrInfo argument specifies the preferred query behaviour,
socket options, or protocol. You can override these conveniently
using Haskell's record update syntax on defaultHints, for example
as follows:

You must provide a Just value for at least one of the HostName
or ServiceName arguments. HostName can be either a numeric
network address (dotted quad for IPv4, colon-separated hex for
IPv6) or a hostname. In the latter case, its addresses will be
looked up unless AI_NUMERICHOST is specified as a hint. If you
do not provide a HostName value and do not set AI_PASSIVE as
a hint, network addresses in the result will contain the address of
the loopback interface.

If the query fails, this function throws an IO exception instead of
returning an empty list. Otherwise, it returns a non-empty list
of AddrInfo values.

There are several reasons why a query might result in several
values. For example, the queried-for host could be multihomed, or
the service might be available via several protocols.

Note: the order of arguments is slightly different to that defined
for getaddrinfo in RFC 2553. The AddrInfo parameter comes first
to make partial application easier.

Bind the socket to an address. The socket must not already be
bound. The Family passed to bind must be the
same as that passed to socket. If the special port number
defaultPort is passed then the system assigns the next available
use port.

Accept a connection. The socket must be bound to an address and
listening for connections. The return value is a pair (conn,
address) where conn is a new socket object usable to send and
receive data on the connection, and address is the address bound
to the socket on the other end of the connection.
On Unix, FD_CLOEXEC is set to the new Socket.

Shut down one or both halves of the connection, depending on the
second argument to the function. If the second argument is
ShutdownReceive, further receives are disallowed. If it is
ShutdownSend, further sends are disallowed. If it is
ShutdownBoth, further sends and receives are disallowed.

Get a file descriptor from a Socket. The socket will never
be closed automatically before withFdSocket completes, but
it may still be closed by an explicit call to close or close',
either before or during the call.

The file descriptor must not be used after withFdSocket returns;
see the documentation for fdSocket to see why that is.

The raw network byte order number is read using host byte order.
Therefore on little-endian architectures the byte order is swapped. For
example 127.0.0.1 is represented as 0x0100007f on little-endian hosts
and as 0x7f000001 on big-endian hosts.

Receive a file descriptor over a UNIX-domain socket. Note that the resulting
file descriptor may have to be put into non-blocking mode in order to be
used safely. See setNonBlockIfNeeded.
Use this function in the case where isUnixDomainSocketAvailable is
True.

This is implemented with SO_PEERCRED on Linux and getpeereid()
on BSD variants. Unfortunately, on some BSD variants
getpeereid() returns unexpected results, rather than an error,
for AF_INET sockets. It is the user's responsibility to make sure
that the socket is a UNIX-domain socket.
Also, on some BSD variants, getpeereid() does not return credentials
for sockets created via socketPair, only separately created and then
explicitly connected UNIX-domain sockets work on such systems.

The name of the host is not looked up.
Instead, a numeric representation of the host's
address is returned. For an IPv4 address, this will be a
dotted-quad string. For IPv6, it will be colon-separated
hexadecimal.

Receive data from the socket. The socket must be in a connected
state. This function may return fewer bytes than specified. If the
message is longer than the specified length, it may be discarded
depending on the type of socket. This function may block until a
message arrives.

Considering hardware and network realities, the maximum number of
bytes to receive should be a small power of 2, e.g., 4096.

The return value is the length of received data. Zero means
EOF. Historical note: Version 2.8.x.y or earlier,
an EOF error was thrown. This was changed in version 3.0.

Send data to the socket. The recipient can be specified
explicitly, so the socket need not be in a connected state.
Returns the number of bytes sent. Applications are responsible for
ensuring that all data has been sent.

Receive data from the socket, writing it into buffer instead of
creating a new string. The socket need not be in a connected
state. Returns (nbytes, address) where nbytes is the number of
bytes received and address is a SockAddr representing the
address of the sending socket.