HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulenetwork-3.2.8.0Haskell2010

Network.Socket

This is the main module of the network package supposed to be used with either Network.Socket.ByteString or Network.Socket.ByteString.Lazy for sending/receiving.

Here are two minimal example programs using the TCP/IP protocol:

  • a server that echoes all data that it receives back

  • a client using it

-- Echo server program
module Main (main) where

import Control.Concurrent (forkFinally)
import qualified Control.Exception as E
import Control.Monad (unless, forever, void)
import qualified Data.ByteString as S
import qualified Data.List.NonEmpty as NE
import Network.Socket
import Network.Socket.ByteString (recv, sendAll)

main :: IO ()
main = runTCPServer Nothing "3000" talk
  where
    talk s = do
        msg <- recv s 1024
        unless (S.null msg) $ do
          sendAll s msg
          talk s

-- from the "network-run" package.
runTCPServer :: Maybe HostName -> ServiceName -> (Socket -> IO a) -> IO a
runTCPServer mhost port server = do
    addr <- resolve
    E.bracket (open addr) close loop
  where
    resolve = do
        let hints = defaultHints {
                addrFlags = [AI_PASSIVE]
              , addrSocketType = Stream
              }
        NE.head <$> getAddrInfo (Just hints) mhost (Just port)
    open addr = E.bracketOnError (openSocket addr) close $ \sock -> do
        setSocketOption sock ReuseAddr 1
        withFdSocket sock setCloseOnExecIfNeeded
        bind sock $ addrAddress addr
        listen sock 1024
        return sock
    loop sock = forever $ E.bracketOnError (accept sock) (close . fst)
        $ \(conn, _peer) -> void $
            -- 'forkFinally' alone is unlikely to fail thus leaking @conn@,
            -- but 'E.bracketOnError' above will be necessary if some
            -- non-atomic setups (e.g. spawning a subprocess to handle
            -- @conn@) before proper cleanup of @conn@ is your case
            forkFinally (server conn) (const $ gracefulClose conn 5000)
{-# LANGUAGE OverloadedStrings #-}
-- Echo client program
module Main (main) where

import qualified Control.Exception as E
import qualified Data.ByteString.Char8 as C
import qualified Data.List.NonEmpty as NE
import Network.Socket
import Network.Socket.ByteString (recv, sendAll)

main :: IO ()
main = runTCPClient "127.0.0.1" "3000" $ \s -> do
    sendAll s "Hello, world!"
    msg <- recv s 1024
    putStr "Received: "
    C.putStrLn msg

-- from the "network-run" package.
runTCPClient :: HostName -> ServiceName -> (Socket -> IO a) -> IO a
runTCPClient host port client = do
    addr <- resolve
    E.bracket (open addr) close client
  where
    resolve = do
        let hints = defaultHints { addrSocketType = Stream }
        NE.head <$> getAddrInfo (Just hints) (Just host) (Just port)
    open addr = E.bracketOnError (openSocket addr) close $ \sock -> do
        connect sock $ addrAddress addr
        return sock

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.

  • 29 types
  • 1 class
  • 68 values
  • Packagenetwork-3.2.8.0
  • Exports224
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceSocket.hs

Address information

1 declaration

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 calls getaddrinfo(3), which never successfully returns with an empty list. If the query fails, getAddrInfo throws an IO exception.

For backwards-compatibility reasons, a hidden GetAddrInfo class is used to make the result polymorphic. It only has instances for [] (lists) and NonEmpty. Use of NonEmpty is recommended.

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:

Example1 expression
let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Stream }

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.

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.

Example3 expressions
import qualified Data.List.NonEmpty as NEaddr <- NE.head <$> getAddrInfo (Just hints) (Just "127.0.0.1") (Just "http")addrAddress addr127.0.0.1:80

Polymorphic version: @since 3.2.3.0

Types

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

typetype ServiceName = String
#

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

valuedefaultHints :: AddrInfo
#

Default hints for address lookup with getAddrInfo.

Example4 expressions
addrFlags defaultHints[]addrFamily defaultHintsAF_UNSPECaddrSocketType defaultHintsNoSocketTypeaddrProtocol defaultHints0

Flags

datadata AddrInfoFlag
#

Flags that control the querying behaviour of getAddrInfo. For more information, see https://tools.ietf.org/html/rfc3493#page-25

Constructors

  • AI_ADDRCONFIG

    The list of returned AddrInfo values will only contain IPv4 addresses if the local system has at least one IPv4 interface configured, and likewise for IPv6. (Only some platforms support this.)

  • AI_ALL

    If AI_ALL is specified, return all matching IPv6 and IPv4 addresses. Otherwise, this flag has no effect. (Only some platforms support this.)

  • AI_CANONNAME

    The addrCanonName field of the first returned AddrInfo will contain the "canonical name" of the host.

  • AI_NUMERICHOST

    The HostName argument must be a numeric address in string form, and network name lookups will not be attempted.

  • AI_NUMERICSERV

    The ServiceName argument must be a port number in string form, and service name lookups will not be attempted. (Only some platforms support this.)

  • AI_PASSIVE

    If no HostName value is provided, the network address in each SockAddr will be left as a "wild card". This is useful for server applications that will accept connections from any client.

  • AI_V4MAPPED

    If an IPv6 lookup is performed, and no IPv6 addresses are found, IPv6-mapped IPv4 addresses will be returned. (Only some platforms support this.)

Instances3Eq, Read, Show

Socket operations

4 declarations
valuebind :: Socket -> SockAddr -> IO ()
#

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.

valuelisten :: Socket -> Int -> IO ()
#

Listen for connections made to the socket. The second argument specifies the maximum number of queued connections and should be at least 1; the maximum value is system-dependent (usually 5).

valueaccept :: Socket -> IO (Socket, SockAddr)
#

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.

Closing

valueclose :: Socket -> IO ()
#

Close the socket. This function does not throw exceptions even if the underlying system call returns errors.

If multiple threads use the same socket and one uses unsafeFdSocket and the other use close, unexpected behavior may happen. For more information, please refer to the documentation of unsafeFdSocket.

valueclose' :: Socket -> IO ()
#

Close the socket. This function throws exceptions if the underlying system call returns errors.

valuegracefulClose :: Socket -> Int -> IO ()
#

Closing a socket gracefully. This sends TCP FIN and check if TCP FIN is received from the peer. The second argument is time out to receive TCP FIN in millisecond. In both normal cases and error cases, socket is deallocated finally.

Since: 3.1.1.0

valueshutdown :: Socket -> ShutdownCmd -> IO ()
#

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.

Socket options

39 declarations
patternpattern Linger :: SocketOption
#

SO_LINGER: timeout in seconds, 0 means disabling/disabled.

patternpattern RecvTimeOut :: SocketOption
#

SO_RCVTIMEO: timeout in microseconds. This option is not useful in the normal case where sockets are non-blocking.

patternpattern SendTimeOut :: SocketOption
#

SO_SNDTIMEO: timeout in microseconds. This option is not useful in the normal case where sockets are non-blocking.

valuewhenSupported :: SocketOption -> IO a -> IO ()
#

Execute the given action only when the specified socket option is supported. Any return value is ignored.

General socket options

datadata StructLinger
#

Low level SO_LINGER option value, which can be used with setSockOpt or setSockOptValue . SockOptValue.

Constructors

Instances4Eq, Ord, Show, Storable

Integrated socket options

Socket

10 declarations
datadata Socket
#

Basic type for a socket.

Instances2Eq, Show
  • Eq SocketDefined in network-3.2.8.0 · Network.Socket.Types
  • Show SocketDefined in network-3.2.8.0 · Network.Socket.Types

Create a new socket using the given address family, socket type and protocol number. The address family is usually AF_INET, AF_INET6, or AF_UNIX. The socket type is usually Stream or Datagram. The protocol number is usually defaultProtocol. If AF_INET6 is used and the socket type is Stream or Datagram, the IPv6Only socket option is set to 0 so that both IPv4 and IPv6 can be handled with one socket.

Example7 expressions
import Network.Socketimport qualified Data.List.NonEmpty as NElet hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_NUMERICSERV], addrSocketType = Stream }addr <- NE.head <$> getAddrInfo (Just hints) (Just "127.0.0.1") (Just "5000")sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)Network.Socket.bind sock (addrAddress addr)getSocketName sock127.0.0.1:5000
valueopenSocket :: AddrInfo -> IO Socket
#

A utility function to open a socket with AddrInfo. This is a just wrapper for the following code:

\addr -> socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
valuewithFdSocket :: Socket -> (CInt -> IO r) -> IO r
#

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, because the Socket may have been garbage-collected, invalidating the file descriptor.

Since: 3.1.0.0

valueunsafeFdSocket :: Socket -> IO CInt
#

Getting a file descriptor from a socket.

If a Socket is shared with multiple threads and one uses unsafeFdSocket, unexpected issues may happen. Consider the following scenario:

1) Thread A acquires a Fd from Socket by unsafeFdSocket.

2) Thread B close the Socket.

3) Thread C opens a new Socket. Unfortunately it gets the same Fd number which thread A is holding.

In this case, it is safer for Thread A to clone Fd by System.Posix.IO.dup. But this would still suffer from a race condition between unsafeFdSocket and close.

If you use this function, you need to guarantee that the Socket does not get garbage-collected until after you finish using the file descriptor. touchSocket can be used for this purpose.

A safer option is to use withFdSocket instead.

valuetouchSocket :: Socket -> IO ()
#

Ensure that the given Socket stays alive (i.e. not garbage-collected) at the given place in the sequence of IO actions. This function can be used in conjunction with unsafeFdSocket to guarantee that the file descriptor is not prematurely freed.

fd <- unsafeFdSocket sock
-- using fd with blocking operations such as accept(2)
touchSocket sock
valuesocketToFd :: Socket -> IO CInt
#

Socket is closed and a duplicated file descriptor is returned. The duplicated descriptor is no longer subject to the possibility of unexpectedly being closed if the socket is finalized. It is now the caller's responsibility to ultimately close the duplicated file descriptor.

Turns a Socket into an Handle. By default, the new handle is unbuffered. Use hSetBuffering to change the buffering.

Note that since a Handle is automatically closed by a finalizer when it is no longer referenced, you should avoid doing any more operations on the Socket after calling socketToHandle. To close the Socket after socketToHandle, call System.IO.hClose on the Handle.

Caveat Handle is not recommended for network programming in Haskell, e.g. merely performing hClose on a TCP socket won't cooperate with peer's gracefulClose, i.e. proper shutdown sequence with appropriate handshakes specified by the protocol.

Types of Socket

Family

newtypenewtype Family
#

Address families. The AF_xxxxx constants are widely used as synonyms for the corresponding PF_xxxxx protocol family values, to which they are numerically equal in mainstream socket API implementations.

Strictly correct usage would be to pass the PF_xxxxx constants as the first argument when creating a Socket, while the AF_xxxxx constants should be used as addrFamily values with getAddrInfo. For now only the AF_xxxxx constants are provided.

Some of the defined patterns may be unsupported on some systems: see isSupportedFamily.

Instances4Eq, Ord, Read, Show
  • Eq FamilyDefined in network-3.2.8.0 · Network.Socket.Types
  • Ord FamilyDefined in network-3.2.8.0 · Network.Socket.Types
  • Read FamilyDefined in network-3.2.8.0 · Network.Socket.Types
  • Show FamilyDefined in network-3.2.8.0 · Network.Socket.Types
patternpattern UnsupportedFamily :: Family
#

Unsupported address family, equal to any other families that are not supported on the system.

patternpattern AF_ROUTE :: Family
#

Internal Routing Protocol (aka AF_NETLINK)

patternpattern AF_OSI :: Family
#

umbrella of all families used by OSI

patternpattern AF_COIP :: Family
#

connection-oriented IP, aka ST II

patternpattern AF_ISDN :: Family
#

Integrated Services Digital Network

Protocol number

Basic socket address type

4 declarations
datadata SockAddr
#

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

Constructors

Instances5Eq, Ord, Show, NFData, SocketAddress
  • Eq SockAddrDefined in network-3.2.8.0 · Network.Socket.Types
  • Ord SockAddrDefined in network-3.2.8.0 · Network.Socket.Types
  • Show SockAddrDefined in network-3.2.8.0 · Network.Socket.Info · orphan
    Example1 expression
    SockAddrInet6 80 0 (0,0,0xffff,0x01020304) 0[::ffff:1.2.3.4]:80
  • NFData SockAddrDefined in network-3.2.8.0 · Network.Socket.Types
  • SocketAddress SockAddrDefined in network-3.2.8.0 · Network.Socket.Types

Host address

typetype HostAddress = Word32
#

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.

For direct manipulation prefer hostAddressToTuple and tupleToHostAddress.

Host address6

Flow Info

Scope ID

Port number

newtypenewtype PortNumber
#

Port number. Use the Num instance (i.e. use a literal) to create a PortNumber value.

Example6 expressions
1 :: PortNumber1read "1" :: PortNumber1show (12345 :: PortNumber)"12345"50000 < (51000 :: PortNumber)True50000 < (52000 :: PortNumber)True50000 + (10000 :: PortNumber)60000
Instances10Bounded, Enum, Eq, Integral, Num, Ord, …

UNIX-domain socket

5 declarations

Whether or not UNIX-domain sockets are available. AF_UNIX is supported on Windows since 3.1.3.0. So, this variable is True on all platforms.

Since 2.7.0.0.

valuesendFd :: Socket -> CInt -> IO ()
#

Send a file descriptor over a UNIX-domain socket. This function does not work on Windows.

valuerecvFd :: Socket -> IO CInt
#

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. This function does not work on Windows.

Getting process ID, user ID and group ID for UNIX-domain sockets.

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.

Since 2.7.0.0.

Name information

2 declarations
valuegetNameInfo
  1. :: [NameInfoFlag]

    flags to control lookup behaviour

  2. -> Bool

    whether to look up a hostname

  3. -> Bool

    whether to look up a service name

  4. -> SockAddr

    the address to look up

  5. -> IO (Maybe HostName, Maybe ServiceName)
#

Resolve an address to a host or service name. This function is protocol independent. The list of NameInfoFlag values controls query behaviour.

If a host or service's name cannot be looked up, then the numeric form of the address or service will be returned.

If the query fails, this function throws an IO exception.

Example2 expressions
addr:_ <- getAddrInfo (Just defaultHints) (Just "127.0.0.1") (Just "http")getNameInfo [NI_NUMERICHOST, NI_NUMERICSERV] True True $ addrAddress addr(Just "127.0.0.1",Just "80")
datadata NameInfoFlag
#

Flags that control the querying behaviour of getNameInfo. For more information, see https://tools.ietf.org/html/rfc3493#page-30

Constructors

  • NI_DGRAM

    Resolve a datagram-based service name. This is required only for the few protocols that have different port numbers for their datagram-based versions than for their stream-based versions.

  • NI_NAMEREQD

    If the hostname cannot be looked up, an IO error is thrown.

  • NI_NOFQDN

    If a host is local, return only the hostname part of the FQDN.

  • NI_NUMERICHOST

    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.

  • NI_NUMERICSERV

    The name of the service is not looked up. Instead, a numeric representation of the service is returned.

Instances3Eq, Read, Show

Low level

0 declarations

socket operations

Sending and receiving data

valuesendBuf :: Socket -> Ptr Word8 -> Int -> IO Int
#

Send data to the socket. The socket must be connected to a remote socket. Returns the number of bytes sent. Applications are responsible for ensuring that all data has been sent.

valuerecvBuf :: Socket -> Ptr Word8 -> Int -> IO Int
#

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.

valuesendBufTo :: Socket -> Ptr a -> Int -> SockAddr -> IO Int
#

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.

valuerecvBufFrom :: Socket -> Ptr a -> Int -> IO (Int, SockAddr)
#

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.

If the first return value is zero, it means EOF.

For Stream sockets, the second return value would be invalid.

NOTE: blocking on Windows unless you compile with -threaded (see GHC ticket #1129)

Advanced IO

valuerecvBufMsg
  1. :: Socket

    Socket

  2. -> [(Ptr Word8, Int)]

    A list of a pair of buffer and its size. If the total length is not large enough, MSG_TRUNC is returned

  3. -> Int

    The buffer size for control messages. If the length is not large enough, MSG_CTRUNC is returned

  4. -> MsgFlag

    Message flags

  5. -> IO (SockAddr, Int, [Cmsg], MsgFlag)

    Source address, received data, control messages and message flags

#

Receive data from the socket using recvmsg(2).

newtypenewtype MsgFlag
#

Message flags. To combine flags, use (<>).

Instances7Eq, Num, Ord, Show, Semigroup, Monoid, …
  • Eq MsgFlagDefined in network-3.2.8.0 · Network.Socket.Flag
  • Num MsgFlagDefined in network-3.2.8.0 · Network.Socket.Flag
  • Ord MsgFlagDefined in network-3.2.8.0 · Network.Socket.Flag
  • Show MsgFlagDefined in network-3.2.8.0 · Network.Socket.Flag
  • Semigroup MsgFlagDefined in network-3.2.8.0 · Network.Socket.Flag
  • Monoid MsgFlagDefined in network-3.2.8.0 · Network.Socket.Flag
  • Bits MsgFlagDefined in network-3.2.8.0 · Network.Socket.Flag
patternpattern MSG_OOB :: MsgFlag
#

Send or receive OOB(out-of-bound) data.

patternpattern MSG_PEEK :: MsgFlag
#

Peek at incoming message without removing it from the queue.

patternpattern MSG_TRUNC :: MsgFlag
#

Received data is truncated. More data exist.

patternpattern MSG_CTRUNC :: MsgFlag
#

Received control message is truncated. More control message exist.

patternpattern MSG_WAITALL :: MsgFlag
#

Wait until the requested number of bytes have been read.

Control message (ancillary data)

datadata Cmsg
#

Control message (ancillary data) including a pair of level and type.

Instances2Eq, Show
  • Eq CmsgDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • Show CmsgDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
datadata CmsgId
#

Identifier of control message (ancillary data).

Constructors

Instances3Eq, Read, Show
  • Eq CmsgIdDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • Read CmsgIdDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • Show CmsgIdDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg

APIs for control message

valuelookupCmsg :: CmsgId -> [Cmsg] -> Maybe Cmsg
#

Locate a control message of the given type in a list of control messages. The following shows an example usage:

(lookupCmsg CmsgIdIPv4TOS cmsgs >>= decodeCmsg) :: Maybe IPv4TOS

Class and types for control message

classclass ControlMessage a where
#

Control message type class. Each control message type has a numeric CmsgId and encode and decode functions.

Instances7ControlMessage, …
newtypenewtype IPv4TTL
#

Time to live of IPv4.

Constructors

Instances4Eq, Show, Storable, ControlMessage
  • Eq IPv4TTLDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • Show IPv4TTLDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • Storable IPv4TTLDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • ControlMessage IPv4TTLDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
newtypenewtype IPv4TOS
#

TOS of IPv4.

Constructors

Instances4Eq, Show, Storable, ControlMessage
  • Eq IPv4TOSDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • Show IPv4TOSDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • Storable IPv4TOSDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg
  • ControlMessage IPv4TOSDefined in network-3.2.8.0 · Network.Socket.Posix.Cmsg

Special constants

1 declaration
valuemaxListenQueue :: Int
#

This is the value of SOMAXCONN, typically 128. 128 is good enough for normal network servers but is too small for high performance servers.

STM to check read and write

4 declarations

Deprecated

1 declaration
valuewithSocketsDo :: 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).