Windows Sockets

An Open Interface for Network Programming under Microsoft Windows

Version 1.1

20 January 1993

Table of Contents


2. PROGRAMMING WITH SOCKETS

2.1 Windows Sockets Stack Installation Checking

To detect the presence of one (or many) Windows Sockets implementations on a system, an application which has been linked with the Windows Sockets Import Library may simply call the WSAStartup() routine. If an application wishes to be a little more sophisticated it can examine the $PATH environment variable and search for instances of Windows Sockets implementations (WINSOCK.DLL). For each instance it can issue a LoadLibrary() call and use the WSAStartup() routine to discover implementation specific data.

This version of the Windows Sockets specification does not attempt to address explicitly the issue of multiple concurrent Windows Sockets implementations. Nothing in the specification should be interpreted as restricting multiple Windows Sockets DLLs from being present and used concurrently by one or more Windows Sockets applications.

For further details of where to obtain Windows Sockets components, see Appendix B.2.

2.2 Sockets

The following material is derived from the document "An Advanced 4.3BSD Interprocess Communication Tutorial" by Samuel J. Leffler, Robert S. Fabry, William N. Joy, Phil Lapsley, Steve Miller, and Chris Torek.

2.2.1 Basic concepts

The basic building block for communication is the socket. A socket is an endpoint of communication to which a name may be bound. Each socket in use has a type and an associated process. Sockets exist within communication domains. A communication domain is an abstraction introduced to bundle common properties of threads communicating through sockets. Sockets normally exchange data only with sockets in the same domain (it may be possible to cross domain boundaries, but only if some translation process is performed). The Windows Sockets facilities support a single communication domain: the Internet domain, which is used by processes which communicate using the Internet Protocol Suite. (Future versions of this specification may include additional domains.)

Sockets are typed according to the communication properties visible to a user. Applications are presumed to communicate only between sockets of the same type, although there is nothing that prevents communication between sockets of different types should the underlying communication protocols support this.

Two types of sockets currently are available to a user. A stream socket provides for the bi-directional, reliable, sequenced, and unduplicated flow of data without record boundaries.

A datagram socket supports bi-directional flow of data which is not promised to be sequenced, reliable, or unduplicated. That is, a process receiving messages on a datagram socket may find messages duplicated, and, possibly, in an order different from the order in which it was sent. An important characteristic of a datagram socket is that record boundaries in data are preserved. Datagram sockets closely model the facilities found in many contemporary packet switched networks such as Ethernet.

2.2.2 Client-server model

The most commonly used paradigm in constructing distributed applications is the client/server model. In this scheme client applications request services from a server application. This implies an asymmetry in establishing communication between the client and server.

The client and server require a well-known set of conventions before service may be rendered (and accepted). This set of conventions comprises a protocol which must be implemented at both ends of a connection. Depending on the situation, the protocol may be symmetric or asymmetric. In a symmetric protocol, either side may play the master or slave roles. In an asymmetric protocol, one side is immutably recognized as the master, with the other as the slave. An example of a symmetric protocol is the TELNET protocol used in the Internet for remote terminal emulation. An example of an asymmetric protocol is the Internet file transfer protocol, FTP. No matter whether the specific protocol used in obtaining a service is symmetric or asymmetric, when accessing a service there is a "client process'' and a "server process''.

A server application normally listens at a well-known address for service requests. That is, the server process remains dormant until a connection is requested by a client's connection to the server's address. At such a time the server process "wakes up'' and services the client, performing whatever appropriate actions the client requests of it. While connection-based services are the norm, some services are based on the use of datagram sockets.

2.2.3 Out-of-band data

Note: The following discussion of out-of-band data, also referred to as TCP Urgent data, follows the model used in the Berkeley software distribution. Users and implementors should be aware of the fact that there are at present two conflicting interpretations of RFC 793 (in which the concept is introduced), and that the implementation of out-of-band data in the Berkeley Software Distribution does not conform to the Host Requirements laid down in RFC 1122. To minimize interoperability problems, applications writers are advised not to use out-of-band data unless this is required in order to interoperate with an existing service. Windows Sockets suppliers are urged to document the out-of-band semantics (BSD or RFC 1122) which their product implements. It is beyond the scope of this specification to mandate a particular set of semantics for out-of-band data handling.

The stream socket abstraction includes the notion of "out of band'' data. Out-of-band data is a logically independent transmission channel associated with each pair of connected stream sockets. Out-of-band data is delivered to the user independently of normal data. The abstraction defines that the out-of-band data facilities must support the reliable delivery of at least one out-of-band message at a time. This message may contain at least one byte of data, and at least one message may be pending delivery to the user at any one time. For communications protocols which support only in-band signaling (i.e. the urgent data is delivered in sequence with the normal data), the system normally extracts the data from the normal data stream and stores it separately. This allows users to choose between receiving the urgent data in order and receiving it out of sequence without having to buffer all the intervening data. It is possible to "peek'' at out-of-band data.

An application may prefer to process out-of-band data "in-line", as part of the normal data stream. This is achieved by setting the socket option SO_OOBINLINE (see section 4.1.21, setsockopt()). In this case, the application may wish to determine whether any of the unread data is "urgent" (the term usually applied to in-line out-of-band data). To facilitate this, the Windows Sockets implementation will maintain a logical "mark" in the data stream indicate the point at which the out-of-band data was sent. An application can use the SIOCATMARK ioctlsocket() command (see section 4.1.12) to determine whether there is any unread data preceding the mark. For example, it might use this to resynchronize with its peer by ensuring that all data up to the mark in the data stream is discarded when appropriate.

The WSAAsyncSelect() routine is particularly well suited to handling notification of the presence of out- of-band-data.

2.2.4 Broadcasting

By using a datagram socket, it is possible to send broadcast packets on many networks supported by the system. The network itself must support broadcast: the system provides no simulation of broadcast in software. Broadcast messages can place a high load on a network, since they force every host on the network to service them. Consequently, the ability to send broadcast packets has been limited to sockets which are explicitly marked as allowing broadcasting. Broadcast is typically used for one of two reasons: it is desired to find a resource on a local network without prior knowledge of its address, or important functions such as routing require that information be sent to all accessible neighbors.

The destination address of the message to be broadcast depends on the network(s) on which the message is to be broadcast. The Internet domain supports a shorthand notation for broadcast on the local network, the address INADDR_BROADCAST. Received broadcast messages contain the senders address and port, as datagram sockets must be bound before use.

Some types of network support the notion of different types of broadcast. For example, the IEEE 802.5 token ring architecture supports the use of link-level broadcast indicators, which control whether broadcasts are forwarded by bridges. The Windows Sockets specification does not provide any mechanism whereby an application can determine the type of underlying network, nor any way to control the semantics of broadcasting.

2.3 Byte Ordering

The Intel byte ordering is like that of the DEC VAX [3], and therefore differs from the Internet and 68000 [4] type processor byte ordering. Thus care must be taken to ensure correct orientation.

Any reference to IP addresses or port numbers passed to or from a Windows Sockets routine must be in network order. This includes the IP address and port fields of a struct sockaddr_in (but not the sin_family field).

Consider an application which normally contacts a server on the TCP port corresponding to the "time" service, but which provides a mechanism for the user to specify that an alternative port is to be used. The port number returned by getservbyname() is already in network order, which is the format required constructing an address, so no translation is required. However if the user elects to use a different port, entered as an integer, the application must convert this from host to network order (using the htons() function) before using it to construct an address. Conversely, if the application wishes to display the number of the port within an address (returned via, e.g., getpeername()), the port number must be converted from network to host order (using ntohs()) before it can be displayed.

Since the Intel and Internet byte orders are different, the conversions described above are unavoidable. Application writers are cautioned that they should use the standard conversion functions provided as part of the Windows Sockets API rather than writing their own conversion code, since future implementations of Windows Sockets are likely to run on systems for which the host order is identical to the network byte order. Only applications which use the standard conversion functions are likely to be portable.

2.4 Socket Options

The socket options supported by Windows Sockets are listed in the pages describing setsockopt() and getsockopt(). A Windows Sockets implementation must recognize all of these options, and (for getsockopt()) return plausible values for each. The default value for each option is shown in the following table.
Value Type Meaning Default Note
SO_ACCEPTCONN BOOL Socket is listen()ing. FALSE unless a listen() has been performed
SO_BROADCAST BOOL Socket is configured for the transmission of broadcast messages. FALSE
SO_DEBUG BOOL Debugging is enabled. FALSE (i)
SO_DONTLINGER BOOL If true, the SO_LINGER option is disabled. TRUE
SO_DONTROUTE BOOL Routing is disabled. FALSE (i)
SO_ERROR int Retrieve error status and clear. 0
SO_KEEPALIVE BOOL Keepalives are being sent. FALSE
SO_LINGER struct linger FAR * Returns the current linger options. l_onoff is 0
SO_OOBINLINE BOOL Out-of-band data is being received in the normal data stream. FALSE
SO_RCVBUF int Buffer size for receives Implementation dependent (i)
SO_REUSEADDR BOOL The address to which this socket is bound can be used by others. FALSE
SO_SNDBUF int Buffer size for sends Implementation dependent (i)
SO_TYPE int The type of the socket (e.g. SOCK_STREAM). As created via socket()
TCP_NODELAY BOOL Disables the Nagle algorithm for send coalescing. Implementation dependent
Notes: (i) An implementation may silently ignore this option on setsockopt() and return a constant value for getsockopt(), or it may accept a value for setsockopt() and return the corresponding value in getsockopt() without using the value in any way.

2.5 Database Files

The getXbyY() [5] and WSAAsyncGetXByY() classes of routines are provided for retrieving network specific information. The getXbyY() routines were originally designed (in the first Berkeley UNIX releases) as mechanisms for looking up information in text databases. Although the information may be retrieved by the Windows Sockets implementation in different ways, a Windows Sockets application requests such information in a consistent manner through either the getXbyY() or the WSAAsyncGetXByY() class of routines.

2.6 Deviation from Berkeley Sockets

There are a few limited instances where the Windows Sockets API has had to divert from strict adherence to the Berkeley conventions, usually because of difficulties of implementation in a Windows environment.

2.6.1 socket data type and error values

A new data type, SOCKET, has been defined. The definition of this type was necessary for future enhancements to the Windows Sockets specification, such as being able to use sockets as file handles in Windows NT [6]. Definition of this type also facilitates porting of applications to a Win/32 environment, as the type will automatically be promoted from 16 to 32 bits.

In UNIX, all handles, including socket handles, are small, non-negative integers, and some applications make assumptions that this will be true. Windows Sockets handles have no restrictions, other than that the value INVALID_SOCKET is not a valid socket. Socket handles may take any value in the range 0 to INVALID_SOCKET-1.

Because the SOCKET type is unsigned, compiling existing source code from, for example, a UNIX environment may lead to compiler warnings about signed/unsigned data type mismatches.

This means, for example, that checking for errors when the socket() and accept() routines return should not be done by comparing the return value with -1, or seeing if the value is negative (both common, and legal, approaches in BSD). Instead, an application should use the manifest constant INVALID_SOCKET as defined in winsock.h. For example:

TYPICAL BSD STYLE:

   s = socket(...);
   if (s == -1)        /* or s < 0 */
       {...}

PREFERRED STYLE:

   s = socket(...);
   if (s == INVALID_SOCKET)
       {...}

2.6.2 select() and FD_*

Because a SOCKET is no longer represented by the UNIX-style "small non-negative integer", the implementation of the select() function was changed in the Windows Sockets API. Each set of sockets is still represented by the fd_set type, but instead of being stored as a bitmask the set is implemented as an array of SOCKETs. To avoid potential problems, applications must adhere to the use of the FD_XXX macros to set, initialize, clear, and check the fd_set structures.

2.6.3 Error codes - errno, h_errno & WSAGetLastError()

Error codes set by the Windows Sockets implementation are NOT made available via the errno variable. Additionally, for the getXbyY() class of functions, error codes are NOT made available via the h_errno variable. Instead, error codes are accessed by using the WSAGetLastError() API described in section 4.3.11. This function is provided in Windows Sockets as a precursor (and eventually an alias) for the Win32 function GetLastError(). This is intended to provide a reliable way for a thread in a multi- threaded process to obtain per-thread error information.

For compatibility with BSD, an application may choose to include a line of the form:

   #define errno WSAGetLastError()
This will allow networking code which was written to use the global errno to work correctly in a single- threaded environment. There are, obviously, some drawbacks. If a source file includes code which inspects errno for both socket and non-socket functions, this mechanism cannot be used. Furthermore, it is not possible for an application to assign a new value to errno. (In Windows Sockets the function WSASetLastError() may be used for this purpose.)

TYPICAL BSD STYLE:

    r = recv(...);
    if (r == -1
        && errno == EWOULDBLOCK)
            {...}
PREFERRED STYLE:
    r = recv(...);
    if (r == -1       /* (but see below) */
        && WSAGetLastError() == EWOULDBLOCK)
            {...}
Although error constants consistent with 4.3 Berkeley Sockets are provided for compatibility purposes, applications should, where possible, use the "WSA" error code definitions. For example, a more accurate version of the above source code fragment is:
    r = recv(...);
    if (r == -1       /* (but see below) */
        && WSAGetLastError() == WSAEWOULDBLOCK)
            {...}

2.6.4 Pointers

All pointers used by applications with Windows Sockets should be FAR. To facilitate this, data type definitions such as LPHOSTENT are provided.

2.6.5 Renamed functions

In two cases it was necessary to rename functions which are used in Berkeley Sockets in order to avoid clashes with other APIs.

2.6.5.1 close() & closesocket()

In Berkeley Sockets, sockets are represented by standard file descriptors, and so the close() function can be used to close sockets as well as regular files. While nothing in the Windows Sockets API prevents an implementation from using regular file handles to identify sockets, nothing requires it either. Socket descriptors are not presumed to correspond to regular file handles, and file operations such as read(), write(), and close() cannot be assumed to work correctly when applied to sockets. Sockets must be closed by using the closesocket() routine. Using the close() routine to close a socket is incorrect and the effects of doing so are undefined by this specification.

2.6.5.2 ioctl() & ioctlsocket()

Various C language run-time systems use the ioctl() routine for purposes unrelated to Windows Sockets. For this reason we have defined the routine ioctlsocket() which is used to handle socket functions which in the Berkeley Software Distribution are performed using ioctl() and fcntl().

2.6.6 Blocking routines & EINPROGRESS

Although blocking operations on sockets are supported under Windows Sockets, their use is strongly discouraged. Programmers who are constrained to use blocking mode - for example, as part of an existing application which is to be ported - should be aware of the semantics of blocking operations in Windows Sockets. See section 3.1.1 for more details.

2.6.7 Maximum number of sockets supported

The maximum number of sockets supported by a particular Windows Sockets supplier is implementation specific. An application should make no assumptions about the availability of a certain number of sockets. This topic is addressed further in section 4.3.15, WSAStartup(). However, independent of the number of sockets supported by a particular implementation is the issue of the maximum number of sockets which an application can actually make use of.

The maximum number of sockets which a Windows Sockets application can make use of is determined at compile time by the manifest constant FD_SETSIZE. This value is used in constructing the fd_set structures used in select() (see section 4.1.18). The default value in winsock.h is 64. If an application is designed to be capable of working with more than 64 sockets, the implementor should define the manifest FD_SETSIZE in every source file before including winsock.h. One way of doing this may be to include the definition within the compiler options in the makefile, for example adding -DFD_SETSIZE=128 as an option to the compiler command line for Microsoft C. It must be emphasized that defining FD_SETSIZE as a particular value has no effect on the actual number of sockets provided by a Windows Sockets implementation.

2.6.8 Include files

For ease of portability of existing Berkeley sockets based source code, a number of standard Berkeley include files are supported. However, these Berkeley header files merely include the winsock.h include file, and it is therefore sufficient (and recommended) that Windows Sockets application source files should simply include winsock.h.

2.6.9 Return values on API failure

The manifest constant SOCKET_ERROR is provided for checking API failure. Although use of this constant is not mandatory, it is recommended. The following example illustrates the use of the SOCKET_ERROR constant:

TYPICAL BSD STYLE:

    r = recv(...);
    if (r == -1     /* or r < 0 */
        && errno == EWOULDBLOCK)
            {...}
PREFERRED STYLE:
    r = recv(...);
    if (r == SOCKET_ERROR
        && WSAGetLastError() == WSAEWOULDBLOCK)
            {...}

2.6.10 Raw Sockets

The Windows Sockets specification does not mandate that a Windows Sockets DLL support raw sockets, that is, sockets opened with SOCK_RAW. However, a Windows Sockets DLL is allowed and encouraged to supply raw socket support. A Windows Sockets-compliant application that wishes to use raw sockets should attempt to open the socket with the socket() call (see section 4.1.23), and if it fails either attempt to use another socket type or indicate the failure to the user.

2.7 Windows Sockets in Multithreaded Versions of Windows

The Windows Sockets interface is designed to work for both single-threaded versions of Windows (such as Windows 3.1) and preemptive multithreaded versions of Windows (such as Windows NT). In a multithreaded environment the sockets interface is basically the same, but the author of a multithreaded application must be aware that it is the responsibility of the application, not the Windows Sockets implementation, to synchronize access to a socket between threads. This is the same rule as applies to other forms of I/O such as file I/O. Failure to synchronize calls on a socket leads to unpredictable results; for example if there are two simultaneous calls to send(), there is no guarantee as to the order in which the data will be sent.

Closing a socket in one thread that has an outstanding blocking call on the same socket in another thread will cause the blocking call to fail with WSAEINTR, just as if the operation were canceled. This also applies if there is a select() call outstanding and the application closes one of the sockets being selected.

There is no default blocking hook installed in preemptive multithreaded versions of Windows. This is because the machine will not be blocked if a single application is waiting for an operation to complete and hence not calling PeekMessage() or GetMessage() which cause the application to yield in nonpremptive Windows. However, for backwards compatibility the WSASetBlockingHook() call is implemented in multithreaded versions of Windows, and any application whose behavior depends on the default blocking hook may install their own blocking hook which duplicates the default hook's semantics, if desired.


NEXT PREVIOUS CONTENTS