Sei sulla pagina 1di 75

WINDOWS SOCKET: PROGRAM EXAMPLES PART 1 Windows Sockets 2 vs Linux Sockets Windows Sockets version 2 (Winsock 2) used to create

advanced Internet, intranet, and other network-capable applications to transmit application data across the wire, network protocol independent for Windows platforms. Winsock follows the Windows Open System Architecture (WOSA) model; it defines a standard service provider interface (SPI: WSP - Winsock Service Provider) between the application programming interface (API: WSA Winsock API), with its exported functions and the protocol stacks. Winsock adapted for Windows starting from Windows Sockets 1.1 using the sockets paradigm that was first used and promoted by Berkeley Software Distribution (BSD) UNIX. That is why when you go through this documents you will find the similarity with Linux/unix Socket discussed in Module 39. Winsock programming previously centered on TCP/IP but some programming practices that worked with TCP/IP do not work with every protocol. As a result, the Windows Sockets 2 API adds functions where necessary to handle several protocols. Windows Sockets 2 is designed to be used by C/C+ + programmers (C++ used in MFC socket programming). Familiarity with Windows networking is required and for lengthy discussion of the TCP/IP, you can refer to Module 42, Linux Sockets. Windows Sockets 2 can be used on all Windows platforms. In this section we will go through the detail of the Winsock functions, structures and macros, and then followed by working program examples. Client and Server Communication There are two distinct types of socket network applications: Server and client. In simple words, servers provide services for clients and other servers whereas clients request services from servers. Servers and clients have different behaviors; therefore, the process of creating them is different. What follows is the general model for creating a streaming TCP/IP server and client. The steps in creating (and difference between) server and client sockets are listed below. Server side programs: 1. 2. 3. 4. 5. 6. 7. Initialize WSA WSAStartup(). Create a socket socket(). Bind the socket bind(). Listen on the socket listen(). Accept a connection accept(), connect(). Send and receive data recv(), send(), recvfrom(), sendto(). Disconnect closesocket().

Client side programs: 1. 2. 3. 4. 5. Initialize WSA WSAStartup(). Create a socket socket(). Connect to the server connect(). Send and receive data recv(), send(), recvfrom(), sendto(). Disconnect closesocket().

Some of the steps are similar for the server and client. These steps are implemented almost exactly alike. The steps in this guide will be specific to the type of application being created. Let explore some of the related functions, structures and macros available for us in Windows Sockets 2 and study the usage in the program examples. Before you can compile and run the Windows Sockets programs you have to include the ws2_32.lib library (or other libraries if needed) because the default installation of the Visual Studio / .Net does not add the library to the project by default. The following steps show how to add more libraries (dependencies) to your project. The first one is for Visual C++ .Net 1.1 and then followed by Visual C++ 6. Depend on the functions/structures/macros used in the programs and these similar steps can be used to add other non-default libraries to your project, else you may encounter a lot of errors during compilation/linking because the definition of the functions/structures/macros cannot be found and resolved. For Visual Studio .Net (Visual C++ .Net 1.1): Select the Project menu and the your_project_name Properties sub menu.

Figure 1 On the left window, expand the Linker folder and select the Input sub folder as shown below. For the Additional Dependencies, select the right empty field.

Figure 2 Type the library name, for this example, ws2_32.lib. Then click the OK button twice to close all the project property pages.

Figure 3 For Visual C++ 6.0, select the Project menu and then Settings sub menu.

Figure 4 On the left window expand the root folder that is your project name and then select the Link tab. At the end of the Object/library modules: field, type the library name as shown below. Click the OK button to close the Project Settings page. Then you are ready to compile and run the program examples that follow. All examples compile and run successfully in Debug mode. If you run for Release mode, there are some errors related to the linking process but that is not our concern here.

Figure 5
Program Example

The following example demonstrates the use of the WSADATA structure and WSAStartup() function. It shows how an application that supports only version 2.2 of Windows Sockets makes a WSAStartup() call.
// // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included... WINVER = 0x0501 for Xp already defined in windows.h

#include <stdio.h> #include <winsock2.h> int main() { WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData); if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The Winsock dll not found!\n"); return 0; } else { printf("The Winsock dll found!\n"); printf("The status: %s.\n", wsaData.szSystemStatus); } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */

/* 2.2 in wVersion since that is the version we */ /* requested. */ if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; } else { printf("The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion)); printf("The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } /* The next task... */ return 0; }

Figure 6 Once an application or DLL has made a successful WSAStartup() call, it can proceed to make other Windows Sockets calls as needed. When it has finished using the services of the WS2_32.DLL, the application or DLL must call WSACleanup() to allow the WS2_32.DLL to free any resources for the application. Details of the actual Windows Sockets implementation are described in the WSADATA structure. An application or DLL can call WSAStartup() more than once if it needs to obtain the WSADATA structure information more than once. On each such call the application can specify any version number supported by the DLL. An application must call one WSACleanup() call for every successful WSAStartup() call to allow third-party DLLs to make use of a WS2_32.DLL on behalf of an application. This means, for example, that if an application calls WSAStartup() three times, it must call WSACleanup() three times. The first two calls to WSACleanup() do nothing except decrement an internal counter; the final WSACleanup() call for the task does all necessary resource de-allocation for the task. WINDOWS SOCKET: PROGRAM EXAMPLES PART 2 socket()
Item Description

Function Use Prototype Parameters Return value Include file Library Remark

socket(). To create a socket that is bound to a specific service provider.


SOCKET socket(int af, int type, int protocol);

See below. See below. <winsock2.h> ws2_32.lib. See below


Table 1

af [in] Address family specification. type

[in] Type specification for the new socket. The following are the only two type specifications supported for Windows Sockets 1.1 and for Winsock 2 there are support for RAW Socket, SOCK_RAW.
Type Meaning

Provides sequenced, reliable, two-way, connection-based byte SOCK_STREAM streams with an OOB data transmission mechanism. Uses TCP (Transport Control Protocol) for the Internet address family. Supports datagrams, which are connectionless, unreliable buffers of SOCK_DGRAM a fixed (typically small) maximum length. Uses UDP (User Datagram Protocol) for the Internet address family.
Table 2

In Windows Sockets 2, many new socket types will be introduced and no longer need to be specified, since an application can dynamically discover the attributes of each available transport protocol through the WSAEnumProtocols() function. Socket type definitions appear in winsock2.h, which will be periodically updated as new socket types, address families, and protocols are defined. protocol [in] Protocol to be used with the socket that is specific to the indicated address family.
Return Values

If no error occurs, socket() returns a descriptor referencing the new socket. Otherwise, a value of INVALID_SOCKET is returned, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

A successful WSAStartup() call must occur before using this WSANOTINITIALISED function. WSAENETDOWN The network subsystem or the associated service provider has failed. WSAEAFNOSUPPORT The specified address family is not supported. A blocking Windows Sockets 1.1 call is in progress, or the service WSAEINPROGRESS provider is still processing a callback function. WSAEMFILE No more socket descriptors are available. WSAENOBUFS No buffer space is available. The socket cannot be created. WSAEPROTONOSUPPORT The specified protocol is not supported. WSAEPROTOTYPE The specified protocol is the wrong type for this socket. WSAESOCKTNOSUPPORT The specified socket type is not supported in this address family.
Table 3 Remarks

The socket() function causes a socket descriptor and any related resources to be allocated and bound to a specific transportservice provider. Winsock will utilize the first available service provider that supports the requested combination of address family, socket type and protocol parameters. The socket that is created will have the overlapped attribute as a default. For Windows, the Microsoft-specific socket option, SO_OPENTYPE, defined in mswsock.h can affect this default. Sockets without the overlapped attribute can be created by using WSASocket(). All functions that allow overlapped operation (WSASend(), WSARecv(), WSASendTo(), WSARecvFrom(), and WSAIoctl()) also support non-overlapped usage on an overlapped socket if the values for parameters related to overlapped operation are null. When selecting a protocol and its supporting service provider this procedure will only choose a base protocol or a protocol chain, not a protocol layer by itself. Unchained protocol layers are not considered to have partial matches on type or af either. That is, they do not lead to an error code of WSAEAFNOSUPPORT or WSAEPROTONOSUPPORT if no suitable protocol is found.
Some note

The manifest constant AF_UNSPEC continues to be defined in the header file but its use is strongly discouraged, as this can cause ambiguity in interpreting the value of the protocol parameter. Connection-oriented sockets such as SOCK_STREAM provide full-duplex connections, and must be in a connected state before any data can be sent or received on it. A connection to another socket is created with a connect() call. Once connected, data can be transferred using send() and recv() calls. When a session has been completed, a closesocket() must be performed. The communications protocols used to implement a reliable, connection-oriented socket ensure that data is not lost or duplicated. If data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, the connection is considered broken and subsequent calls will fail with the error code set to WSAETIMEDOUT.

Connectionless, message-oriented sockets allow sending and receiving of datagrams to and from arbitrary peers using sendto() and recvfrom(). If such a socket is connected to a specific peer, datagrams can be sent to that peer using send() and can be received only from this peer using recv(). Support for sockets with type SOCK_RAW (RAW socket) is not required, but service providers are encouraged to support raw sockets as practicable. On Windows NT, raw socket support requires administrative privileges.
Notes for IrDA Sockets

Keep the following in mind: The af_irda.h header file must be explicitly included. Only SOCK_STREAM is supported; the SOCK_DGRAM type is not supported by IrDA. The protocol parameter is always set to 0 for IrDA.

Program Example // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h

#include <stdio.h> #include <winsock2.h> int main() { WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData); if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The Winsock dll not found!\n"); return 0; } else { printf("The Winsock dll found!\n"); printf("The status: %s.\n", wsaData.szSystemStatus); } /* /* /* /* /* if { Confirm that the WinSock DLL supports 2.2. */ Note that if the DLL supports versions greater */ than 2.2 in addition to 2.2, it will still return */ 2.2 in wVersion since that is the version we */ requested. */ (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)

/* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; } else { printf("The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));

printf("The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } //////////Create a socket//////////////////////// //Create a SOCKET object called m_socket. SOCKET m_socket; // Call the socket function and return its value to the m_socket variable. // For this application, use the Internet address family, streaming sockets, and // the TCP/IP protocol. // using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4 m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (m_socket == INVALID_SOCKET) { printf("Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("socket() is OK!\n"); } return 0; }

Figure 1 bind()
Item Description

Function Use Prototype

bind(). Associates a local address with a socket.


int bind(SOCKET s, const struct sockaddr* name, int namelen);

s [in] Descriptor identifying an unbound socket. Parameters name [in] Address to assign to the socket from the sockaddr structure.

namelen [in] Length of the value in the name parameter, in bytes. Return value See below. Include file <winsock2.h.> ws2_32.lib Library Remark See below.
Table 4 Return Values

If no error occurs, bind() returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

WSANOTINITIALISED A successful WSAStartup() call must occur before using this function. WSAENETDOWN The network subsystem has failed.

WSAEACCES

WSAEADDRINUSE

WSAEADDRNOTAVAIL WSAEFAULT

WSAEINPROGRESS WSAEINVAL WSAENOBUFS WSAENOTSOCK

Attempt to connect datagram socket to broadcast address failed because setsockopt() option SO_BROADCAST is not enabled. A process on the computer is already bound to the same fully-qualified address and the socket has not been marked to allow address reuse with SO_REUSEADDR. For example, the IP address and port are bound in the AF_INET case). (See the SO_REUSEADDR socket option under setsockopt().) The specified address is not a valid address for this computer. The name or namelen parameter is not a valid part of the user address space, the namelen parameter is too small, the name parameter contains an incorrect address format for the associated address family, or the first two bytes of the memory block specified by name does not match the address family associated with the socket descriptor s. A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. The socket is already bound to an address. Not enough buffers available, too many connections. The descriptor is not a socket.
Table 5

Remarks

The bind() function is used on an unconnected socket before subsequent calls to the connect() or listen() functions. It is used to bind to either connection-oriented (stream TCP Transmission Control Protocol) or connectionless (datagram UDP User Datagram Protocol) sockets. When a socket is created with a call to the socket() function, it exists in a namespace (address family), but it has no name assigned to it. Use the bind() function to establish the local association of the socket by assigning a local name to an unnamed socket. A name consists of three parts when using the Internet address family: The address family. A host address. A port number that identifies the application.

In Windows Sockets 2, the name parameter is not strictly interpreted as a pointer to a sockaddr structure. It is cast this way for Windows Sockets 1.1 compatibility. Service providers are free to regard it as a pointer to a block of memory of size namelen. The first 2 bytes in this block (corresponding to the sa_family member of the sockaddr structure) must contain the address family that was used to create the socket. Otherwise, an error WSAEFAULT occurs. If an application does not care what local address is assigned, specify the manifest constant value ADDR_ANY for the sa_data member of the name parameter. This allows the underlying service provider to use any appropriate network address, potentially simplifying application programming in the presence of multihomed hosts that is, hosts that have more than one network interface and address. For TCP/IP, if the port is specified as zero, the service provider assigns a unique port to the application with a value between 1024 and 5000. The application can use getsockname() after calling bind() to learn the address and the port that has been assigned to it. If the Internet address is equal to INADDR_ANY, getsockname() cannot necessarily supply the address until the socket is connected, since several addresses can be valid if the host is multihomed. Binding to a specific port number other than port 0 is discouraged for client applications, since there is a danger of conflicting with another socket already using that port number. When using bind() with the SO_EXCLUSIVEADDR or SO_REUSEADDR socket option, the socket option must be set prior to executing bind() to have any affect.
Program Example // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h

#include <stdio.h> #include <winsock2.h> int main() {

WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData); if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The Winsock dll not found!\n"); return 0; } else { printf("The Winsock dll found!\n"); printf("The status: %s.\n", wsaData.szSystemStatus); } /* /* /* /* /* if { Confirm that the WinSock DLL supports 2.2.*/ Note that if the DLL supports versions greater */ than 2.2 in addition to 2.2, it will still return */ 2.2 in wVersion since that is the version we */ requested. */ (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)

/* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; } else { printf("The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); printf("The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } //////////Create a socket//////////////////////// //Create a SOCKET object called m_socket. SOCKET m_socket; // Call the socket function and return its value to the m_socket variable. // For this application, use the Internet address family, streaming sockets, and // the TCP/IP protocol. // using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4 m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (m_socket == INVALID_SOCKET) { printf("Error at socket(): %ld.\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("socket() is OK!\n"); } ////////////////bind()////////////////////////////// // Create a sockaddr_in object and set its values. sockaddr_in service; // AF_INET is the Internet address family. service.sin_family = AF_INET; // "127.0.0.1" is the local IP address to which the socket will be bound. service.sin_addr.s_addr = inet_addr("127.0.0.1"); // 55555 is the port number to which the socket will be bound. service.sin_port = htons(55555);

// Call the bind function, passing the created socket and the sockaddr_in structure as parameters. // Check for general errors. if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("bind() failed: %ld.\n", WSAGetLastError()); closesocket(m_socket); return 0; } else { printf("bind() is OK!\n"); } return 0; }

Figure 2 Another example demonstrates the use of the bind() function.


#include <stdio.h> #include <winsock2.h> int main() { // Initialize Winsock WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != NO_ERROR) printf("Error at WSAStartup().\n"); else printf("Winsock dll is available.\n"); // Create a SOCKET for listening for // incoming connection requests SOCKET ListenSocket; ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("Error at socket(): %ld.\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("socket() is OK!\n"); } // The sockaddr_in structure specifies the address family, // IP address, and port for the socket that is being bound. sockaddr_in service; // Address family - internet IPv4 service.sin_family = AF_INET; // IP address service.sin_addr.s_addr = inet_addr("127.0.0.1"); // Port number service.sin_port = htons(55555); // Bind the socket. if (bind( ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) {

printf("bind() failed.\n"); closesocket(ListenSocket); return 0; } else { printf("bind() is OK!\n"); } WSACleanup(); return 0; }

Figure 3
Notes for IrDA Sockets

Infrared Data Association, a term commonly referred to as IrDA, can be described as: A protocol suite designed to provide wireless, walk-up, line-of-sight connectivity between devices. The semi-transparent red window found on many laptops and some desktop computers. An organization that creates, promotes, and standardizes IrDA technology (got to irda.org for more information on the IrDA organization). The af_irda.h header file must be explicitly included. Local names are not exposed in IrDA. IrDA client sockets therefore, must never call the bind function before the connect() function. If the IrDA socket was previously bound to a service name using bind, the connect function will fail with SOCKET_ERROR. If the service name is of the form "LSAP-SELxxx," where xxx is a decimal integer in the range 1-127, the address indicates a specific LSAP-SEL xxx rather than a service name. Service names such as these allow server applications to accept incoming connections directed to a specific LSAP-SEL, without first performing an ISA service name query to get the associated LSAP-SEL. One example of this service name type is a non-Windows device that does not support IAS.

closesocket()
Item Description

Function Use Prototype Parameters

closesocket(). Closes an existing socket.


int closesocket(SOCKET s);

s [in] Descriptor identifying the socket to close. Return value See below. Include file <winsock2.h> ws2_32.lib Library Remark See below.
Table 6 Return Values

If no error occurs, closesocket() returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

WSANOTINITIALISED A successful WSAStartup() call must occur before using this function. WSAENETDOWN The network subsystem has failed. WSAENOTSOCK The descriptor is not a socket. A blocking Windows Sockets 1.1 call is in progress, or the service provider WSAEINPROGRESS is still processing a callback function.

WSAEINTR WSAEWOULDBLOCK

The (blocking) Windows Socket 1.1 call was canceled through WSACancelBlockingCall(). The socket is marked as non-blocking and SO_LINGER is set to a nonzero time-out value.
Table 7

Remarks

The closesocket() function closes a socket. Use it to release the socket descriptor s so that further references to s fail with the error WSAENOTSOCK. If this is the last reference to an underlying socket, the associated naming information and queued data are discarded. Any pending blocking, asynchronous calls issued by any thread in this process are canceled without posting any notification messages. Any pending overlapped send and receive operations ( WSASend()/ WSASendTo()/ WSARecv()/ WSARecvFrom() with an overlapped socket) issued by any thread in this process are also canceled. Any event, completion routine, or completion port action specified for these overlapped operations is performed. The pending overlapped operations fail with the error status WSA_OPERATION_ABORTED. An application should always have a matching call to closesocket() for each successful call to socket() to return any socket resources to the system. The semantics of closesocket are affected by the socket options SO_LINGER and SO_DONTLINGER as follows (SO_DONTLINGER is enabled by default; SO_LINGER is disabled).
Option Interval Type of close Wait for close?

SO_DONTLINGER Do not care SO_LINGER Zero SO_LINGER Nonzero


Table 8

Graceful Hard Graceful

No No Yes

If SO_LINGER is set with a zero time-out interval (that is, the linger structure members l_onoff is not zero and l_linger is zero), closesocket() is not blocked even if queued data has not yet been sent or acknowledged. This is called a hard or abortive close, because the socket's virtual circuit is reset immediately, and any unsent data is lost. Any recv() call on the remote side of the circuit will fail with WSAECONNRESET. If SO_LINGER is set with a nonzero time-out interval on a blocking socket, the closesocket() call blocks on a blocking socket until the remaining data has been sent or until the time-out expires. This is called a graceful disconnect. If the time-out expires before all data has been sent, the Windows Sockets implementation terminates the connection before closesocket() returns. Enabling SO_LINGER with a nonzero time-out interval on a non-blocking socket is not recommended. In this case, the call to closesocket() will fail with an error of WSAEWOULDBLOCK if the close operation cannot be completed immediately. If closesocket() fails with WSAEWOULDBLOCK the socket handle is still valid, and a disconnect is not initiated. The application must call closesocket() again to close the socket. If SO_DONTLINGER is set on a stream socket by setting the l_onoff member of the LINGER structure to zero, the closesocket() call will return immediately and does not receive WSAEWOULDBLOCK whether the socket is blocking or non-blocking. However, any data queued for transmission will be sent, if possible, before the underlying socket is closed. This is also called a graceful disconnect. In this case, the Windows Sockets provider cannot release the socket and other resources for an arbitrary period, thus affecting applications that expect to use all available sockets. This is the default behavior (SO_DONTLINGER is set by default).
Some Note

To assure that all data is sent and received on a connection, an application should call shutdown() before calling closesocket(). Also note, an FD_CLOSE network event is not posted after closesocket() is called. Here is a summary of closesocket() behavior: If SO_DONTLINGER is enabled (the default setting) it always returns immediately - connection is gracefully closed in the background. If SO_LINGER is enabled with a zero time-out: it always returns immediately - connection is reset/terminated. If SO_LINGER is enabled with a nonzero time-out: With a blocking socket, it blocks until all data sent or time-out expires. With a non-blocking socket, it returns immediately indicating failure.

Notes for IrDA Sockets

For IrDA, keep the following in mind: The af_irda.h header file must be explicitly included.

The standard linger options are supported. Although IrDA does not provide a graceful close, IrDA will defer closing until receive queues are purged. Thus, an application can send data and immediately call the socket function, and be confident that the receiver will copy the data before receiving an FD_CLOSE message.

Notes for ATM

The following are important issues associated with connection teardown when using Asynchronous Transfer Mode (ATM) and Windows Sockets 2: Using the closesocket() or shutdown() functions with SD_SEND or SD_BOTH results in a RELEASE signal being sent out on the control channel. Due to ATM's use of separate signal and data channels, it is possible that a RELEASE signal could reach the remote end before the last of the data reaches its destination, resulting in a loss of that data. One possible solutions is programming a sufficient delay between the last data sent and the closesocket() or shutdown() function calls for an ATM socket. Half close is not supported by ATM. Both abortive and graceful disconnects result in a RELEASE signal being sent out with the same cause field. In either case, received data at the remote end of the socket is still delivered to the application. WINDOWS SOCKET: PROGRAM EXAMPLES PART 3 listen()
Item Description

Function Use Prototype

listen().
int listen(SOCKET s, int backlog);

Places a socket in a state in which it is listening for an incoming connection. s [in] Descriptor identifying a bound, unconnected socket.

backlog [in] Maximum length of the queue of pending connections. If set to SOMAXCONN, the underlying service provider responsible for socket s will set the backlog to a maximum reasonable value. There is no standard provision to obtain the actual backlog value. Return value See below. Include file <winsock2.h> ws2_32.lib Library Remark See below. Parameters
Table 1 Return Values

If no error occurs, listen() returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

A successful WSAStartup() call must occur before using this WSANOTINITIALISED function. WSAENETDOWN The network subsystem has failed. The socket's local address is already in use and the socket was not marked to allow address reuse with SO_REUSEADDR. This error usually occurs during execution of the bind() function, but could WSAEADDRINUSE be delayed until this function if the bind was to a partially wildcard address (involving ADDR_ANY) and if a specific address needs to be committed at the time of this function. A blocking Windows Sockets 1.1 call is in progress, or the service WSAEINPROGRESS provider is still processing a callback function. WSAEINVAL The socket has not been bound with bind(). WSAEISCONN The socket is already connected. WSAEMFILE No more socket descriptors are available. WSAENOBUFS No buffer space is available. WSAENOTSOCK The descriptor is not a socket.

WSAEOPNOTSUPP

The referenced socket is not of a type that supports the listen operation.
Table 2

Remarks

To accept connections, a socket is first created with the socket() function and bound to a local address with the bind() function, a backlog for incoming connections is specified with listen(), and then the connections are accepted with the accept() function. Sockets that are connection oriented those of type SOCK_STREAM for example, are used with listen(). The socket s is put into passive mode where incoming connection requests are acknowledged and queued pending acceptance by the process. The listen() function is typically used by servers that can have more than one connection request at a time. If a connection request arrives and the queue is full, the client will receive an error with an indication of WSAECONNREFUSED. If there are no available socket descriptors, listen() attempts to continue to function. If descriptors become available, a later call to listen() or accept() will refill the queue to the current or most recent backlog, if possible, and resume listening for incoming connections. An application can call listen() more than once on the same socket. This has the effect of updating the current backlog for the listening socket. Should there be more pending connections than the new backlog value, the excess pending connections will be reset and dropped. For IrDA sockets the af_irda.h header file must be explicitly included.
Compatibility

The backlog parameter is limited (silently) to a reasonable value as determined by the underlying service provider. Illegal values are replaced by the nearest legal value. There is no standard provision to find out the actual backlog value.
Program Example // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h

#include <stdio.h> #include <winsock2.h> int main() { WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData); if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The Winsock dll not found!\n"); return 0; } else { printf("The Winsock dll found!\n"); printf("The status: %s.\n", wsaData.szSystemStatus); } /* /* /* /* /* if { Confirm that the WinSock DLL supports 2.2.*/ Note that if the DLL supports versions greater */ than 2.2 in addition to 2.2, it will still return */ 2.2 in wVersion since that is the version we */ requested. */ (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )

/* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; } else { printf("The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); printf("The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } //////////Create a socket//////////////////////// //Create a SOCKET object called m_socket. SOCKET m_socket; // Call the socket function and return its value to the m_socket variable. // For this application, use the Internet address family, streaming sockets, and // the TCP/IP protocol. // using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4 m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (m_socket == INVALID_SOCKET) { printf("Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("socket() is OK!\n"); } ////////////////bind()////////////////////////////// // Create a sockaddr_in object and set its values. sockaddr_in service; // AF_INET is the Internet address family. service.sin_family = AF_INET; // "127.0.0.1" is the local IP address to which the socket will be bound. service.sin_addr.s_addr = inet_addr("127.0.0.1"); // 55555 is the port number to which the socket will be bound. service.sin_port = htons(55555); // Call the bind function, passing the created socket and the sockaddr_in structure as parameters. // Check for general errors. if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("bind() failed: %ld.\n", WSAGetLastError()); closesocket(m_socket); return 0; } else { printf("bind() is OK!\n"); } // Call the listen function, passing the created socket and the maximum number of allowed // connections to accept as parameters. Check for general errors. if (listen( m_socket, 1) == SOCKET_ERROR) printf("listen(): Error listening on socket %ld.\n", WSAGetLastError()); else { printf("listen() is OK, I'm waiting for connections...\n"); } return 0; }

Figure 1 Another example that demonstrates the use of the listen() function.
Program Example #include <stdio.h> #include <winsock2.h> int main() { // Initialize Winsock WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) printf("Server: Error at WSAStartup().\n"); else printf("Server: WSAStartup() is OK!\n"); // Create a SOCKET for listening for // incoming connection requests. SOCKET ListenSocket; ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("Server: Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else printf("Server: socket() is OK.\n"); // The sockaddr_in structure specifies the address family, // IP address, and port for the socket that is being bound. sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr("127.0.0.1"); service.sin_port = htons(55555); if (bind(ListenSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("Server: bind() failed.\n"); closesocket(ListenSocket); return 0; } else printf("Server: bind() is OK.\n"); // Listen for incoming connection requests // on the created socket if (listen(ListenSocket, 1) == SOCKET_ERROR) printf("Server: listen(): Error listening on socket.\n"); printf("Server: I'm listening on socket, waiting for connection...\n"); WSACleanup(); return 0; }

Figure 2 At this time our server is listening for connection on port 55555 but it still cant accept (establish) connection from clients or other servers. accept()
Item Description

Function Use Prototype

accept(). Permits an incoming connection attempt on a socket.


SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);

s [in] Descriptor that identifies a socket that has been placed in a listening state with the listen() function. The connection is actually made with the socket that is returned by accept. Parameters addr [out] Optional pointer to a buffer that receives the address of the connecting entity, as known to the communications layer. The exact format of the addr parameter is determined by the address family that was established when the socket from the sockaddr() structure was created.

addrlen [in, out] Optional pointer to an integer that contains the length of addr. Return value Se below. Include file <winsock2.h> ws2_32.lib Library Remark See below.
Table 3 Return Values

If no error occurs, accept() returns a value of type SOCKET that is a descriptor for the new socket. This returned value is a handle for the socket on which the actual connection is made. Otherwise, a value of INVALID_SOCKET is returned, and a specific error code can be retrieved by calling WSAGetLastError(). The integer referred to by addrlen initially contains the amount of space pointed to by addr. On return it will contain the actual length in bytes of the address returned.
Error code Meaning

WSANOTINITIALISED A successful WSAStartup() call must occur before using this function. An incoming connection was indicated, but was subsequently terminated by the WSAECONNRESET remote peer prior to accepting the call. The addrlen parameter is too small or addr is not a valid part of the user address WSAEFAULT space. A blocking Windows Sockets 1.1 call was canceled through WSAEINTR WSACancelBlockingCall(). WSAEINVAL The listen() function was not invoked prior to accept. A blocking Windows Sockets 1.1 call is in progress, or the service provider is WSAEINPROGRESS still processing a callback function. The queue is nonempty upon entry to accept and there are no descriptors WSAEMFILE available. WSAENETDOWN The network subsystem has failed. WSAENOBUFS No buffer space is available. WSAENOTSOCK The descriptor is not a socket. WSAEOPNOTSUPP The referenced socket is not a type that supports connection-oriented service. The socket is marked as non-blocking and no connections are present to be WSAEWOULDBLOCK accepted.

Table 4 Remarks

The accept() function extracts the first connection on the queue of pending connections on socket s. It then creates and returns a handle to the new socket. The newly created socket is the socket that will handle the actual connection; it has the same properties as socket s, including the asynchronous events registered with the WSAAsyncSelect() or WSAEventSelect() functions. The accept() function can block the caller until a connection is present if no pending connections are present on the queue, and the socket is marked as blocking. If the socket is marked as non-blocking and no pending connections are present on the queue, accept() returns an error as described in the following. After the successful completion of accept() returns a new socket handle, the accepted socket cannot be used to accept more connections. The original socket remains open and listens for new connection requests. The parameter addr is a result parameter that is filled in with the address of the connecting entity, as known to the communications layer. The exact format of the addr parameter is determined by the address family in which the communication is occurring. The addrlen is a value-result parameter; it should initially contain the amount of space pointed to by addr; on return it will contain the actual length (in bytes) of the address returned. The accept() function is used with connection-oriented socket types such as SOCK_STREAM. If addr and/or addrlen are equal to NULL, then no information about the remote address of the accepted socket is returned.
Program Example // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h

#include <stdio.h> #include <winsock2.h> int main() { WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData); if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The Winsock dll not found!\n"); return 0; } else { printf("Server: The Winsock dll found!\n"); printf("Server: The status: %s.\n", wsaData.szSystemStatus); } /* /* /* /* /* if { Confirm that the WinSock DLL supports 2.2.*/ Note that if the DLL supports versions greater */ than 2.2 in addition to 2.2, it will still return */ 2.2 in wVersion since that is the version we */ requested. */ (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )

/* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; }

else { printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); printf("Server: The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } //////////Create a socket//////////////////////// //Create a SOCKET object called m_socket. SOCKET m_socket; // Call the socket function and return its value to the m_socket variable. // For this application, use the Internet address family, streaming sockets, and // the TCP/IP protocol. // using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4 m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (m_socket == INVALID_SOCKET) { printf("Server: Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("Server: socket() is OK!\n"); } ////////////////bind////////////////////////////// // Create a sockaddr_in object and set its values. sockaddr_in service; // AF_INET is the Internet address family. service.sin_family = AF_INET; // "127.0.0.1" is the local IP address to which the socket will be bound. service.sin_addr.s_addr = inet_addr("127.0.0.1"); // 55555 is the port number to which the socket will be bound. // using the htons for big-endian service.sin_port = htons(55555); // Call the bind function, passing the created socket and the sockaddr_in structure as parameters. // Check for general errors. if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("Server: bind() failed: %ld.\n", WSAGetLastError()); closesocket(m_socket); return 0; } else { printf("Server: bind() is OK!\n"); } // Call the listen function, passing the created socket and the maximum number of allowed // connections to accept as parameters. Check for general errors. if (listen(m_socket, 1) == SOCKET_ERROR) printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError()); else { printf("Server: listen() is OK, I'm waiting for connections...\n"); } // Create a temporary SOCKET object called AcceptSocket for accepting connections. SOCKET AcceptSocket; // Create a continuous loop that checks for connections requests. If a connection // request occurs, call the accept function to handle the request. printf("Server: Waiting for a client to connect...\n"); printf("***Hint: Server is ready...run your client program...***\n"); // Do some verification... while (1) {

AcceptSocket = SOCKET_ERROR; while (AcceptSocket == SOCKET_ERROR) { AcceptSocket = accept(m_socket, NULL, NULL); } // else, accept the connection... // When the client connection has been accepted, transfer control from the // temporary socket to the original socket and stop checking for new connections. printf("Server: Client Connected!\n"); m_socket = AcceptSocket; break; } return 0; }

Figure 3 We can verify the connection listening and waiting using netstat command on Windows console as shown below. Make sure you do not terminate the previous program.

Figure 4 The following is another example demonstrates the use of the accept() function. Press the Ctrl + C to terminate the server program.
Program Example #include <stdio.h> #include <winsock2.h> int main()

{ // Initialize Winsock. WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != NO_ERROR) printf("Server: Error at WSAStartup().\n"); else printf("Server: WSAStartup() is OK.\n"); // Create a SOCKET for listening for // incoming connection requests. SOCKET ListenSocket; ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("Server: Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else printf("Server: socket() is OK.\n"); // The sockaddr_in structure specifies the address family, // IP address, and port for the socket that is being bound. sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr("127.0.0.1"); service.sin_port = htons(55555); if (bind(ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) { printf("Server: bind() failed.\n"); closesocket(ListenSocket); return 0; } else printf("Server: bind() is OK.\n"); // Listen for incoming connection requests. // on the created socket if (listen(ListenSocket, 10) == SOCKET_ERROR) printf("Server: Error listening on socket.\n"); else printf("Server: listen() is OK.\n"); // Create a SOCKET for accepting incoming requests. SOCKET AcceptSocket; printf("Server: Waiting for client to connect...\n"); // Accept the connection if any... while(1) { AcceptSocket = SOCKET_ERROR; while(AcceptSocket == SOCKET_ERROR) { AcceptSocket = accept(ListenSocket, NULL, NULL); } printf("Server: accept() is OK.\n"); printf("Server: Client connected...ready for communication.\n"); ListenSocket = AcceptSocket; break; } WSACleanup(); return 0; }

Figure 5 Now we can test our client-server communication by running both, the server and the client programs. In this example we test both programs on the same computer. You can try testing them on the network computer or Internet domain by changing the IP address (you can use hostname as well by adding some codes such as gethostname() etc.). Create a new project for the client program.
Program Example // // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h A sample of client program

#include <stdio.h> #include <winsock2.h> int main() { // Initialize Winsock. WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) printf("Client: Error at WSAStartup().\n"); else printf("Client: WSAStartup() is OK.\n"); // Create a socket. SOCKET m_socket; m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_socket == INVALID_SOCKET) { printf("Client: socket() - Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else printf("Client: socket() is OK.\n"); // Connect to a server. sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(55555); if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) { printf("Client: connect() - Failed to connect.\n"); WSACleanup(); return 0; } // Send and receive data. int bytesSent; int bytesRecv = SOCKET_ERROR;

// Be careful with the array bound, provide some checking mechanism char sendbuf[200] = "Client: Sending some test string to server..."; char recvbuf[200] = ""; bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); printf("Client: send() - Bytes Sent: %ld\n", bytesSent); while(bytesRecv == SOCKET_ERROR) { bytesRecv = recv(m_socket, recvbuf, 32, 0); if (bytesRecv == 0 || bytesRecv == WSAECONNRESET) { printf("Client: Connection Closed.\n"); break; } else printf("Client: recv() is OK.\n"); if (bytesRecv < 0) return 0; else printf("Client: Bytes received - %ld.\n", bytesRecv); } return 0; }

When we just run the client program, the following is the output.

Figure 6 Next, run the previous server program and then run the client program. The Windows console outputs for the server and the client are shown below. In this example the server just accepts the connection from client and do not read the clients sent string (data). Server console output:

Figure 7 Client console output: The error code 10054 is WSAECONNRESET- An existing connection was forcibly closed by the remote host. That is OK for the error at this stage.

Figure 8

WINDOWS SOCKET: PROGRAM EXAMPLES PART 4 Sending and Receiving Data The following code demonstrates the send() and recv() functions (TCP packet). For server program:
int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[200] = "Hello! Im server, sending some test data."; char recvbuf[200] = ""; bytesRecv = recv(m_socket, recvbuf, 32, 0); printf("Bytes Recv: %ld\n", bytesRecv); bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); printf("Bytes Sent: %ld\n", bytesSent);

For client program:


int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[200] = "Hello! Im client, sending some test data."; char recvbuf[200] = ""; bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); printf("Bytes Sent: %ld\n", bytesSent); while(bytesRecv == SOCKET_ERROR) { bytesRecv = recv(m_socket, recvbuf, 32, 0); if (bytesRecv == 0 || bytesRecv == WSAECONNRESET) { printf("Connection Closed.\n"); break; } if (bytesRecv < 0) return; printf("Bytes Recv: %ld\n", bytesRecv); }

In this code, two integers are used to keep track of the number of bytes that are sent and received. The send() and recv() functions both return an integer value of the number of bytes sent or received, respectively, or an error. Each function also takes the same parameters: the active socket, a char buffer, and the number of bytes to send or receive, and any flags to use. Use recvfrom() and sendto() functions for the connectionless socket such as for the User Datagram Protocol (UDP). The following is our complete send, receive and read data for the client and server program examples. Firstly we run the server program to listen for connection.
Program Example // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h

// Server program, using TCP #include <stdio.h> #include <winsock2.h> int main() { WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData); if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The Winsock dll not found!\n"); return 0; } else { printf("Server: The Winsock dll found!\n"); printf("Server: The status: %s.\n", wsaData.szSystemStatus); } /* /* /* /* /* if { Confirm that the WinSock DLL supports 2.2.*/ Note that if the DLL supports versions greater */ than 2.2 in addition to 2.2, it will still return */ 2.2 in wVersion since that is the version we */ requested. */ (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )

/* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; } else { printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); printf("Server: The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } //////////Create a socket//////////////////////// //Create a SOCKET object called m_socket. SOCKET m_socket; // Call the socket function and return its value to the m_socket variable. // For this application, use the Internet address family, streaming sockets, and // the TCP/IP protocol. // using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4 m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (m_socket == INVALID_SOCKET) { printf("Server: Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("Server: socket() is OK!\n"); } ////////////////bind////////////////////////////// // Create a sockaddr_in object and set its values. sockaddr_in service; // AF_INET is the Internet address family.

service.sin_family = AF_INET; // "127.0.0.1" is the local IP address to which the socket will be bound. service.sin_addr.s_addr = inet_addr("127.0.0.1"); // 55555 is the port number to which the socket will be bound. service.sin_port = htons(55555); // Call the bind function, passing the created socket and the sockaddr_in structure as parameters. // Check for general errors. if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("Server: bind() failed: %ld.\n", WSAGetLastError()); closesocket(m_socket); return 0; } else { printf("Server: bind() is OK!\n"); } // Call the listen function, passing the created socket and the maximum number of allowed // connections to accept as parameters. Check for general errors. if (listen(m_socket, 10) == SOCKET_ERROR) printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError()); else { printf("Server: listen() is OK, I'm waiting for connections...\n"); } // Create a temporary SOCKET object called AcceptSocket for accepting connections. SOCKET AcceptSocket; // Create a continuous loop that checks for connections requests. If a connection // request occurs, call the accept function to handle the request. printf("Server: Waiting for a client to connect...\n" ); printf("***Hint: Server is ready...run your client program...***\n"); // Do some verification... while (1) { AcceptSocket = SOCKET_ERROR; while (AcceptSocket == SOCKET_ERROR) { AcceptSocket = accept(m_socket, NULL, NULL); } // else, accept the connection... // When the client connection has been accepted, transfer control from the // temporary socket to the original socket and stop checking for new connections. printf("Server: Client Connected!\n"); m_socket = AcceptSocket; break; } int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[200] = "This string is a test data from server"; // initialize to empty data... char recvbuf[200] = ""; // Send some test string to client... printf("Server: Sending some test data to client...\n"); bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); if (bytesSent == SOCKET_ERROR) printf("Server: send() error %ld.\n", WSAGetLastError()); else { printf("Server: send() is OK.\n"); printf("Server: Bytes Sent: %ld.\n", bytesSent); } // Receives some test string from client...and client // must send something lol... bytesRecv = recv(m_socket, recvbuf, 200, 0);

if (bytesRecv == SOCKET_ERROR) printf("Server: recv() error %ld.\n", WSAGetLastError()); else { printf("Server: recv() is OK.\n"); printf("Server: Received data is: \"%s\"\n", recvbuf); printf("Server: Bytes received: %ld.\n", bytesRecv); } WSACleanup(); return 0; }

Figure 1 The server program is listening to and waiting for connection. Next we run the following client program.
Program Example // // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h A sample of client program using TCP

#include <stdio.h> #include <winsock2.h> int main() { // Initialize Winsock. WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) printf("Client: Error at WSAStartup().\n"); else printf("Client: WSAStartup() is OK.\n"); // Create a socket. SOCKET m_socket; m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_socket == INVALID_SOCKET) { printf("Client: socket() - Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else printf("Client: socket() is OK.\n"); // Connect to a server. sockaddr_in clientService; clientService.sin_family = AF_INET; // Just test using the localhost, you can try other IP address

clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(55555); if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) { printf("Client: connect() - Failed to connect.\n"); WSACleanup(); return 0; } else { printf("Client: connect() is OK.\n"); printf("Client: Can start sending and receiving data...\n"); } // Send and receive data. int bytesSent; int bytesRecv = SOCKET_ERROR; // Be careful with the array bound, provide some checking mechanism... char sendbuf[200] = "This is a test string from client"; char recvbuf[200] = ""; // Receives some test string to server... while(bytesRecv == SOCKET_ERROR) { bytesRecv = recv(m_socket, recvbuf, 200, 0); if (bytesRecv == 0 || bytesRecv == WSAECONNRESET) { printf("Client: Connection Closed.\n"); break; } if (bytesRecv < 0) return 0; else { printf("Client: recv() is OK.\n"); printf("Client: Received data is: \"%s\"\n", recvbuf); printf("Client: Bytes received is: %ld.\n", bytesRecv); } } // Sends some test data to server... bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); if(bytesSent == SOCKET_ERROR) printf("Client: send() error %ld.\n", WSAGetLastError()); else { printf("Client: send() is OK - Bytes sent: %ld\n", bytesSent); printf("Client: The test string sent: \"%s\"\n", sendbuf); } WSACleanup(); return 0; }

Figure 2 And the previous server console output is shown below that complete the server-client communication.

Figure 3 Try running the client program from different machines and change the server IP address accordingly. Another more flexible client-server program example is given at the end of this note.
Notes for ATM

The following are important issues associated with connection setup, and must be considered when using Asynchronous Transfer Mode (ATM) with Windows Sockets 2: The accept() and WSAAccept() functions do not necessarily set the remote address and address length parameters. Therefore, when using ATM, the caller should use the WSAAccept() function and place ATM_CALLING_PARTY_NUMBER_IE in the ProviderSpecific member of the QOS structure, which itself is included in the lpSQOS parameter of the callback function used in accordance with WSAAccept(). When using the accept() function, realize that the function may return before connection establishment has traversed the entire distance between sender and receiver. This is because the accept() function returns as soon as it receives a CONNECT ACK message; in ATM, a CONNECT ACK message is returned by the next switch in the path as soon as a CONNECT message is processed (rather than the CONNECT ACK being sent by the end node to which the connection is ultimately established). As such, applications should realize that if data is sent immediately following receipt of a CONNECT ACK message, data loss is possible, since the connection may not have been established all the way between sender and receiver.

connect()
Item Description

Function Use Prototype

connect(). Establishes a connection to a specified socket.


int connect(SOCKET s, const struct sockaddr* name, int namelen);

s [in] Descriptor identifying an unconnected socket. Parameters name [in] Name of the socket in the sockaddr structure to which the connection should be established.

namelen [in] Length of name, in bytes. Return value See below. Include file <winsock2.h> ws2_32.lib Library Remark See below.
Table 1 Return Values

If no error occurs, connect() returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError(). On a blocking socket, the return value indicates success or failure of the connection attempt. With a non-blocking socket, the connection attempt cannot be completed immediately. In this case, connect() will return SOCKET_ERROR, and WSAGetLastError() will return WSAEWOULDBLOCK. In this case, there are three possible scenarios: Use the select() function to determine the completion of the connection request by checking to see if the socket is writeable. If the application is using WSAAsyncSelect() to indicate interest in connection events, then the application will receive an FD_CONNECT notification indicating that the connect operation is complete (successfully or not). If the application is using WSAEventSelect() to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).

Until the connection attempt completes on a non-blocking socket, all subsequent calls to connect() on the same socket will fail with the error code WSAEALREADY, and WSAEISCONN when the connection completes successfully. Due to ambiguities in version 1.1 of the Windows Sockets specification, error codes returned from connect() while a connection is already pending may vary among implementations. As a result, it is not recommended that applications use multiple calls to connect() to detect connection completion. If they do, they must be prepared to handle WSAEINVAL and WSAEWOULDBLOCK error values the same way that they handle WSAEALREADY, to assure robust execution. If the error code returned indicates the connection attempt failed (that is, WSAECONNREFUSED, WSAENETUNREACH, WSAETIMEDOUT) the application can call connect() again for the same socket.
Error code Meaning

WSANOTINITIALISED A successful WSAStartup() call must occur before using this function. WSAENETDOWN The network subsystem has failed. The socket's local address is already in use and the socket was not marked to allow address reuse with SO_REUSEADDR. This error usually occurs when WSAEADDRINUSE executing bind(), but could be delayed until this function if the bind was to a partially wildcard address (involving ADDR_ANY) and if a specific address needs to be committed at the time of this function. The blocking Windows Socket 1.1 call was canceled through WSAEINTR WSACancelBlockingCall(). A blocking Windows Sockets 1.1 call is in progress, or the service provider is WSAEINPROGRESS still processing a callback function. A non-blocking connect call is in progress on the specified socket. In order to preserve backward compatibility, this error is reported as WSAEALREADY WSAEINVAL to Windows Sockets 1.1 applications that link to either Winsock.dll or Wsock32.dll. WSAEADDRNOTAVAIL The remote address is not a valid address (such as ADDR_ANY). WSAEAFNOSUPPORT Addresses in the specified family cannot be used with this socket. WSAECONNREFUSED The attempt to connect was forcefully rejected. The name or the namelen parameter is not a valid part of the user address space, WSAEFAULT the namelen parameter is too small, or the name parameter contains incorrect address format for the associated address family. WSAEINVAL The parameter s is a listening socket. WSAEISCONN The socket is already connected (connection-oriented sockets only). WSAENETUNREACH The network cannot be reached from this host at this time. WSAENOBUFS No buffer space is available. The socket cannot be connected. WSAENOTSOCK The descriptor is not a socket. WSAETIMEDOUT Attempt to connect timed out without establishing a connection. The socket is marked as non-blocking and the connection cannot be completed WSAEWOULDBLOCK immediately. Attempt to connect datagram socket to broadcast address failed because WSAEACCES setsockopt() option SO_BROADCAST is not enabled.
Table 2 Remarks

The connect() function is used to create a connection to the specified destination. If socket s, is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound. For connection-oriented sockets (for example, type SOCK_STREAM), an active connection is initiated to the foreign host using name (an address in the namespace of the socket). If a socket is opened, a setsockopt() call is made, and then a sendto() call is made, Windows Sockets performs an implicit bind() function call. When the socket call completes

successfully, the socket is ready to send and receive data. If the address member of the structure specified by the name parameter is all zeroes, connect will return the error WSAEADDRNOTAVAIL. Any attempt to reconnect an active connection will fail with the error code WSAEISCONN. For connection-oriented, non-blocking sockets, it is often not possible to complete the connection immediately. In such a case, this function returns the error WSAEWOULDBLOCK. However, the operation proceeds. When the success or failure outcome becomes known, it may be reported in one of two ways, depending on how the client registers for notification. If the client uses the select() function, success is reported in the writefds set and failure is reported in the exceptfds set. If the client uses the functions WSAAsyncSelect() or WSAEventSelect(), the notification is announced with FD_CONNECT and the error code associated with the FD_CONNECT indicates either success or a specific reason for failure.

For a connectionless socket (for example, type SOCK_DGRAM), the operation performed by connect() is merely to establish a default destination address that can be used on subsequent send()/ WSASend() and recv()/ WSARecv() calls. Any datagrams received from an address other than the destination address specified will be discarded. If the address member of the structure specified by name is all zeroes, the socket will be disconnected. Then, the default remote address will be indeterminate, so send()/ WSASend() and recv()/ WSARecv() calls will return the error code WSAENOTCONN. However, sendto()/ WSASendTo() and recvfrom()/ WSARecvFrom() can still be used. The default destination can be changed by simply calling connect again, even if the socket is already connected. Any datagrams queued for receipt are discarded if name is different from the previous connect. For connectionless sockets, name can indicate any valid address, including a broadcast address. However, to connect to a broadcast address, a socket must use setsockopt() to enable the SO_BROADCAST option. Otherwise, connect will fail with the error code WSAEACCES. When a connection between sockets is broken, the sockets should be discarded and recreated. When a problem develops on a connected socket, the application must discard and recreate the needed sockets in order to return to a stable point.
Program Example

The following example demonstrates the use of the connect() function for client and server. Firstly run the server program and then the client.
// // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h Server program, using TCP

#include <stdio.h> #include <winsock2.h> int main() { WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData); if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The Winsock dll not found!\n"); return 0; } else { printf("Server: The Winsock dll found!\n"); printf("Server: The status: %s.\n", wsaData.szSystemStatus); }

/* /* /* /* /* if {

Confirm that the WinSock DLL supports 2.2.*/ Note that if the DLL supports versions greater */ than 2.2 in addition to 2.2, it will still return */ 2.2 in wVersion since that is the version we */ requested. */ (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )

/* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; } else { printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); printf("Server: The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } //////////Create a socket//////////////////////// //Create a SOCKET object called m_socket. SOCKET m_socket; // Call the socket function and return its value to the m_socket variable. // For this application, use the Internet address family, streaming sockets, and // the TCP/IP protocol. // using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4 m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (m_socket == INVALID_SOCKET) { printf("Server: Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("Server: socket() is OK!\n"); } ////////////////bind////////////////////////////// // Create a sockaddr_in object and set its values. sockaddr_in service; // AF_INET is the Internet address family. service.sin_family = AF_INET; // "127.0.0.1" is the local IP address to which the socket will be bound. // Try your machine IP address... service.sin_addr.s_addr = inet_addr("127.0.0.1"); // 55555 is the port number to which the socket will be bound // Try other non-standard ports ( > 1024). Max = 2 power to 16 = 65536 service.sin_port = htons(55555); // Call the bind function, passing the created socket and the sockaddr_in structure as parameters. // Check for general errors. if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("Server: bind() failed: %ld.\n", WSAGetLastError()); closesocket(m_socket); return 0; } else { printf("Server: bind() is OK!\n"); } // Call the listen function, passing the created socket and the maximum number of allowed // connections to accept as parameters. Check for general errors. if (listen(m_socket, 10) == SOCKET_ERROR) printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError()); else

{ printf("Server: listen() is OK, I'm waiting for connections...\n"); } // Create a temporary SOCKET object called AcceptSocket for accepting connections. SOCKET AcceptSocket; // Create a continuous loop that checks for connections requests. If a connection // request occurs, call the accept function to handle the request. printf("Server: Waiting for a client to connect...\n" ); printf("***Hint: Server is ready...run your client program...***\n"); // Do some verification... while (1) { AcceptSocket = SOCKET_ERROR; while (AcceptSocket == SOCKET_ERROR) { AcceptSocket = accept(m_socket, NULL, NULL); } // else, accept the connection... // When the client connection has been accepted, transfer control from the // temporary socket to the original socket and stop checking for new connections. printf("Server: Client Connected!\n"); m_socket = AcceptSocket; break; } WSACleanup(); return 0; }

Figure 4
Program Example

The following is the client program to test the previous connect() function.
#include <stdio.h> #include <winsock2.h> int main() { // Initialize Winsock WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) printf("Client: Error at WSAStartup().\n"); else printf("Client: WSAStartup() is OK.\n"); // Create a SOCKET for connecting to server SOCKET ConnectSocket; ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ConnectSocket == INVALID_SOCKET) { printf("Client: Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else

printf("Client: socket() is OK.\n"); // The sockaddr_in structure specifies the address family, // IP address, and port of the server to be connected to. sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(55555); // Connect to server... if (connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) { printf("Client: Failed to connect.\n"); WSACleanup(); return 0; } else printf("Client: connect() is OK.\n"); printf("Client: Connected to server...\n"); WSACleanup(); return 0; }

Figure 5 And the previous server programs console output is shown below.

Figure 6 Notes for IrDA Sockets: The af_irda.h header file must be explicitly included. If an existing IrDA connection is detected at the media-access level, WSAENETDOWN is returned. If active connections to a device with a different address exist, WSAEADDRINUSE is returned. If the socket is already connected or an exclusive/multiplexed mode change failed, WSAEISCONN is returned. If the socket was previously bound to a local service name to accept incoming connections using bind(), WSAEINVAL is returned. Note that once a socket is bound, it cannot be used for establishing an outbound connection.

IrDA implements the connect function with addresses of the form sockaddr_irda. Typically, a client application will create a socket with the socket() function, scan the immediate vicinity for IrDA devices with the IRLMP_ENUMDEVICES socket option, and choose a device from the returned list, form an address and then call connect(). There is no difference between blocking and non-blocking semantics. WINDOWS SOCKET: PROGRAM EXAMPLES PART 5 recv()

Item

Description

Function Use Prototype

recv(). Receives data from a connected or bound socket.


int recv(SOCKET s, char* buf, int len, int flags);

s [in] Descriptor identifying a connected socket. buf [out] Buffer for the incoming data. Parameters len [in] Length of buf, in bytes flags [in] Flag specifying the way in which the call is made. Return value Include file Library Remark See below. <winsock2.h> ws2_32.lib See below.
Table 1 Return Values

If no error occurs, recv() returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

WSANOTINITIALISED A successful WSAStartup() call must occur before using this function. WSAENETDOWN The network subsystem has failed. The buf parameter is not completely contained in a valid part of the user WSAEFAULT address space. WSAENOTCONN The socket is not connected. WSAEINTR The (blocking) call was canceled through WSACancelBlockingCall(). A blocking Windows Sockets 1.1 call is in progress, or the service provider is WSAEINPROGRESS still processing a callback function. The connection has been broken due to the keep-alive activity detecting a WSAENETRESET failure while the operation was in progress. WSAENOTSOCK The descriptor is not a socket. MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, OOB data is not supported in the communication domain WSAEOPNOTSUPP associated with this socket, or the socket is unidirectional and supports only send operations. The socket has been shut down; it is not possible to receive on a socket after WSAESHUTDOWN shutdown() has been invoked with how set to SD_RECEIVE or SD_BOTH. WSAEWOULDBLOCK The socket is marked as non-blocking and the receive operation would block. WSAEMSGSIZE The message was too large to fit into the specified buffer and was truncated. The socket has not been bound with bind(), or an unknown flag was WSAEINVAL specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled or (for byte stream sockets only) len was zero or negative. The virtual circuit was terminated due to a time-out or other failure. The WSAECONNABORTED application should close the socket as it is no longer usable. The connection has been dropped because of a network failure or because the WSAETIMEDOUT peer system failed to respond. The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket as it is no longer usable. On a WSAECONNRESET UDP-datagram socket this error would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message.
Table 2 Remarks

The recv() function is used to read incoming data on connection-oriented sockets, or connectionless sockets. When using a connection-oriented protocol, the sockets must be connected before calling recv(). When using a connectionless protocol, the sockets must be bound before calling recv(). The local address of the socket must be known. For server applications, use an explicit bind() function or an implicit accept() or WSAAccept() function. Explicit binding is discouraged for client applications. For client applications, the socket can become bound implicitly to a local address using connect(), WSAConnect(), sendto(), WSASendTo(), or WSAJoinLeaf(). For connected or connectionless sockets, the recv() function restricts the addresses from which received messages are accepted. The function only returns messages from the remote address specified in the connection. Messages from other addresses are (silently) discarded. For connection-oriented sockets (type SOCK_STREAM for example), calling recv() will return as much information as is currently availableup to the size of the buffer specified. If the socket has been configured for in-line reception of OOB data (socket option SO_OOBINLINE) and OOB data is yet unread, only OOB data will be returned. The application can use the ioctlsocket() or WSAIoctl() SIOCATMARK command to determine whether any more OOB data remains to be read. For connectionless sockets (type SOCK_DGRAM or other message-oriented sockets), data is extracted from the first enqueued datagram (message) from the destination address specified by the connect() function. If the datagram or message is larger than the buffer specified, the buffer is filled with the first part of the datagram, and recv() generates the error WSAEMSGSIZE. For unreliable protocols (for example, UDP) the excess data is lost; for reliable protocols, the data is retained by the service provider until it is successfully read by calling recv() with a large enough buffer. If no incoming data is available at the socket, the recv() call blocks and waits for data to arrive according to the blocking rules defined for WSARecv() with the MSG_PARTIAL flag not set unless the socket is non-blocking. In this case, a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK. The select(), WSAAsyncSelect(), or WSAEventSelect() functions can be used to determine when more data arrives. If the socket is connection oriented and the remote side has shut down the connection gracefully, and all data has been received, a recv() will complete immediately with zero bytes received. If the connection has been reset, a recv() will fail with the error WSAECONNRESET. The flags parameter can be used to influence the behavior of the function invocation beyond the options specified for the associated socket. The semantics of this function are determined by the socket options and the flags parameter. The latter is constructed by using the bitwise OR operator with any of the following values.
Value Meaning

Peeks at the incoming data. The data is copied into the buffer but is not removed from the input queue. The function subsequently returns the amount of data that can be read in a single call to the recv() (or recvfrom()) function, which may not be the same MSG_PEEK as the total amount of data queued on the socket. The amount of data that can actually be read in a single call to the recv() (or recvfrom()) function is limited to the data size written in the send() or sendto() function call. MSG_OOB Processes Out Of Band (OOB) data.
Table 3 Program Example

The following example demonstrates the use of the recv() function on server and client.
// // // // // // // // // // Microsoft Copyright Microsoft Copyright Development Environment 2003 - Version 7.1.3088 (r) 1987-2002 Microsoft Corporation. All Right Reserved .NET Framework 1.1 - Version 1.1.4322 (r) 1998-2002 Microsoft Corporation. All Right Reserved

Run on Windows XP Pro machine, version 2002, SP 2 <windows.h> already included WINVER = 0x0501 for Xp already defined in windows.h Server program, using TCP

#include <stdio.h> #include <winsock2.h> int main() { WORD wVersionRequested; WSADATA wsaData; int wsaerr; // Using MAKEWORD macro, Winsock version request 2.2 wVersionRequested = MAKEWORD(2, 2); wsaerr = WSAStartup(wVersionRequested, &wsaData);

if (wsaerr != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The Winsock dll not found!\n"); return 0; } else { printf("Server: The Winsock dll found!\n"); printf("Server: The status: %s.\n", wsaData.szSystemStatus); } /* /* /* /* /* if { Confirm that the WinSock DLL supports 2.2.*/ Note that if the DLL supports versions greater */ than 2.2 in addition to 2.2, it will still return */ 2.2 in wVersion since that is the version we */ requested. */ (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )

/* Tell the user that we could not find a usable */ /* WinSock DLL.*/ printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); WSACleanup(); return 0; } else { printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); printf("Server: The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } //////////Create a socket//////////////////////// //Create a SOCKET object called m_socket. SOCKET m_socket; // Call the socket function and return its value to the m_socket variable. // For this application, use the Internet address family, streaming sockets, and // the TCP/IP protocol. // using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4 m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (m_socket == INVALID_SOCKET) { printf("Server: Error at socket(): %ld\n", WSAGetLastError()); WSACleanup(); return 0; } else { printf("Server: socket() is OK!\n"); } ////////////////bind////////////////////////////// // Create a sockaddr_in object and set its values. sockaddr_in service; // AF_INET is the Internet address family. service.sin_family = AF_INET; // "127.0.0.1" is the local IP address to which the socket will be bound. service.sin_addr.s_addr = inet_addr("127.0.0.1"); // 55555 is the port number to which the socket will be bound. service.sin_port = htons(55555); // Call the bind function, passing the created socket and the sockaddr_in structure as parameters. // Check for general errors. if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("Server: bind() failed: %ld.\n", WSAGetLastError()); closesocket(m_socket); return 0;

} else { printf("Server: bind() is OK!\n"); } // Call the listen function, passing the created socket and the maximum number of allowed // connections to accept as parameters. Check for general errors. if (listen(m_socket, 10) == SOCKET_ERROR) printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError()); else { printf("Server: listen() is OK, I'm waiting for connections...\n"); } // Create a temporary SOCKET object called AcceptSocket for accepting connections. SOCKET AcceptSocket; // Create a continuous loop that checks for connections requests. If a connection // request occurs, call the accept function to handle the request. printf("Server: Waiting for a client to connect...\n" ); printf("***Hint: Server is ready...run your client program...***\n"); // Do some verification... while (1) { AcceptSocket = SOCKET_ERROR; while (AcceptSocket == SOCKET_ERROR) { AcceptSocket = accept(m_socket, NULL, NULL); } // else, accept the connection... // When the client connection has been accepted, transfer control from the // temporary socket to the original socket and stop checking for new connections. printf("Server: Client Connected!\n"); m_socket = AcceptSocket; break; } int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[200] = "This string is a test data from server"; // initialize to empty data... char recvbuf[200] = ""; // Send some test string to client... printf("Server: Sending some test data to client...\n"); bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); if (bytesSent == SOCKET_ERROR) printf("Server: send() error %ld.\n", WSAGetLastError()); else { printf("Server: send() is OK.\n"); printf("Server: Bytes Sent: %ld.\n", bytesSent); } // Receives some test string from client...and client // must send something lol... bytesRecv = recv(m_socket, recvbuf, 200, 0); if (bytesRecv == SOCKET_ERROR) printf("Server: recv() error %ld.\n", WSAGetLastError()); else { printf("Server: recv() is OK.\n"); printf("Server: Received data is: \"%s\"\n", recvbuf); printf("Server: Bytes received: %ld.\n", bytesRecv); } WSACleanup(); return 0; }

Figure 1 The following is the client program. As usual, you have to run the server program first.
#include <stdio.h> #include <winsock2.h> int main() { // Initialize Winsock WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) printf("Client: Error at WSAStartup().\n"); else printf("Client: WSAStartup() is OK.\n"); // Create a SOCKET for connecting to server SOCKET ConnectSocket; ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ConnectSocket == INVALID_SOCKET) { printf("Client: Error at socket(): %ld.\n", WSAGetLastError()); WSACleanup(); return 0; } else printf("Client: socket() is OK.\n"); // The sockaddr_in structure specifies the address family, // IP address, and port of the server to be connected to. sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(55555); // Connect to server. if (connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) { printf("Client: Failed to connect.\n"); WSACleanup(); return 0; } else printf("Client: connect() is OK.\n"); // Declare and initialize variables. int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[100] = "Client: Sending some data."; char recvbuf[100] = ""; while(bytesRecv == SOCKET_ERROR ) { bytesRecv = recv(ConnectSocket, recvbuf, 100, 0); if (bytesRecv == 0 || bytesRecv == WSAECONNRESET) { printf("Client: Connection Closed.\n"); break; }

else { printf("Client: recv() is OK.\n"); printf("Client: Bytes received: %ld\n", bytesRecv); } } // Send and receive data. bytesSent = send(ConnectSocket, sendbuf, strlen(sendbuf), 0); printf("Client: Bytes sent: %ld\n", bytesSent); WSACleanup(); return 0; }

Figure 2 And the previous servers console output.

Figure 3 send()
Item Description

Function Use Prototype

send(). Sends data on a connected socket.


int send(SOCKET s, const char* buf, int len, int flags);

s [in] Descriptor identifying a connected socket. buf [in] Buffer containing the data to be transmitted. Parameters len [in] Length of the data in buf, in bytes. flags [in] Indicator specifying the way in which the call is made. Return value Include file See below. <winsock2.h>

Library Remark

ws2_32.lib See below.


Table 4

Return Values

If no error occurs, send returns the total number of bytes sent, which can be less than the number indicated by len. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

WSANOTINITIALISED A successful WSAStartup() call must occur before using this function. WSAENETDOWN The network subsystem has failed. The requested address is a broadcast address, but the appropriate flag was not WSAEACCES set. Call setsockopt() with the SO_BROADCAST socket option to enable use of the broadcast address. A blocking Windows Sockets 1.1 call was canceled through WSAEINTR WSACancelBlockingCall(). A blocking Windows Sockets 1.1 call is in progress, or the service provider is WSAEINPROGRESS still processing a callback function. The buf parameter is not completely contained in a valid part of the user address WSAEFAULT space. The connection has been broken due to the keep-alive activity detecting a failure WSAENETRESET while the operation was in progress. WSAENOBUFS No buffer space is available. WSAENOTCONN The socket is not connected. WSAENOTSOCK The descriptor is not a socket. MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, OOB data is not supported in the communication domain WSAEOPNOTSUPP associated with this socket, or the socket is unidirectional and supports only receive operations. The socket has been shut down; it is not possible to send on a socket after WSAESHUTDOWN shutdown() has been invoked with how set to SD_SEND or SD_BOTH. WSAEWOULDBLOCK The socket is marked as non-blocking and the requested operation would block. The socket is message oriented, and the message is larger than the maximum WSAEMSGSIZE supported by the underlying transport. WSAEHOSTUNREACH The remote host cannot be reached from this host at this time. The socket has not been bound with bind(), or an unknown flag was specified, WSAEINVAL or MSG_OOB was specified for a socket with SO_OOBINLINE enabled. The virtual circuit was terminated due to a time-out or other failure. The WSAECONNABORTED application should close the socket as it is no longer usable. The virtual circuit was reset by the remote side executing a hard or abortive close. For UPD sockets, the remote host was unable to deliver a previously sent WSAECONNRESET UDP datagram and responded with a "Port Unreachable" ICMP packet. The application should close the socket as it is no longer usable. The connection has been dropped, because of a network failure or because the WSAETIMEDOUT system on the other end went down without notice.
Table 5

Remarks The send() function is used to write outgoing data on a connected socket. For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying provider, which can be obtained by using getsockopt() to retrieve the value of socket option SO_MAX_MSG_SIZE. If the data is too long to pass atomically through the underlying protocol, the error WSAEMSGSIZE is returned, and no data is transmitted. The successful completion of a send does not indicate that the data was successfully delivered. If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in non-blocking mode. On non-blocking stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both client and server computers. The select(), WSAAsyncSelect() or WSAEventSelect() functions can be used to determine when it is possible to send more data. Calling send with a zero len parameter is permissible and will be treated by implementations as successful. In such cases, send() will return zero as a valid value. For message-oriented sockets, a zero-length transport datagram is sent. The flags parameter can be used to influence the behavior of the function beyond the options specified for the associated socket. The

semantics of this function are determined by the socket options and the flags parameter. The latter is constructed by using the bitwise OR operator with any of the following values.
Value Meaning

MSG_DONTROUTE Specifies that the data should not be subject to routing. A Windows Sockets service provider can choose to ignore this flag. MSG_OOB Sends OOB data (stream-style socket such as SOCK_STREAM only.
Table 6

For IrDA Sockets the af_irda.h header file must be explicitly included. WINDOWS SOCKET: PROGRAM EXAMPLES PART 6 Socket Options You can use the getsockopt() and setsockopt() functions for more getting and setting socket options. To enumerate protocols and discover supported properties for each installed protocol, use the WSAEnumProtocols() function. The following socket option levels are available: IPPROTO_IP IPPROTO_IPV6 IPPROTO_RM IPPROTO_TCP IPPROTO_UDP NSPROTO_IPX SOL_APPLETALK SOL_IRLMP SOL_SOCKET Please refer to MSDN documentation for the details. All SO_* socket options apply equally to IPv4 and IPv6 (except SO_BROADCAST, since broadcast is not implemented in IPv6). setsockopt()
Item Description

Function Use

setsockopt(). Sets a socket option.


int setsockopt( SOCKET s, int level, int optname, const char* optval, int optlen);

Prototype

s [in] Descriptor identifying a socket. level [in] Level at which the option is defined. Example: SOL_SOCKET. optname [in] Socket option for which the value is to be set. Example: SO_BROADCAST. The optname value must be a socket option defined within the specified level, or behavior is undefined. optval [in] Pointer to the buffer in which the value for the requested option is specified. optlen [in] Size of the optval buffer, in bytes. Return value See below. Include file <winsock2.h> ws2_32.lib. Library Remark See below.
Table 1 Return Values

Parameters

If no error occurs, setsockopt() returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

A successful WSAStartup() call must occur before using this WSANOTINITIALISED function. WSAENETDOWN The network subsystem has failed. optval is not in a valid part of the process address space or optlen WSAEFAULT parameter is too small. A blocking Windows Sockets 1.1 call is in progress, or the service WSAEINPROGRESS provider is still processing a callback function. WSAEINVAL level is not valid, or the information in optval is not valid. WSAENETRESET Connection has timed out when SO_KEEPALIVE is set. The option is unknown or unsupported for the specified provider or WSAENOPROTOOPT socket. WSAENOTCONN Connection has been reset when SO_KEEPALIVE is set. WSAENOTSOCK The descriptor is not a socket.
Table 2

Remarks

The setsockopt() function sets the current value for a socket option associated with a socket of any type, in any state. Although options can exist at multiple protocol levels, they are always present at the uppermost socket level. Options affect socket operations, such as whether expedited data (Out-of-Band (OOB) data for example) is received in the normal data stream, and whether broadcast messages can be sent on the socket. If the setsockopt() function is called before the bind() function, TCP/IP options will not be checked with TCP/IP until the bind() occurs. In this case, the setsockopt() function call will always succeed, but the bind() function call may fail because of an early setsockopt() failing. If a socket is opened, a setsockopt() call is made, and then a sendto() call is made, Windows Sockets performs an implicit bind() function call. There are two types of socket options: Boolean options that enable or disable a feature or behavior, and options that require an integer value or structure. To enable a Boolean option, optval points to a nonzero integer. To disable the option optval points to an integer equal to zero. The optlen parameter should be equal to sizeof(int) for Boolean options. For other options, optval points to an integer or structure that contains the desired value for the option, and optlen is the length of the integer or structure. The following options are supported for setsockopt(). For default values of these options, see the description. The Type identifies the type of data addressed by optval. For level = SOL_SOCKET
Value Type Meaning

SO_BROADCAST

BOOL

SO_CONDITIONAL_ACCEPT BOOL SO_DEBUG SO_DONTLINGER BOOL BOOL

SO_DONTROUTE SO_GROUP_PRIORITY SO_KEEPALIVE SO_LINGER SO_OOBINLINE SO_RCVBUF SO_REUSEADDR

BOOL int BOOL LINGER BOOL int BOOL

Enables transmission and receipt of broadcast messages on the socket. Enables sockets to delay the acknowledgment of a connection until after the WSAAccept() condition function is called. Records debugging information. Does not block close waiting for unsent data to be sent. Setting this option is equivalent to setting SO_LINGER with l_onoff set to zero. Does not route: sends directly to interface. Succeeds but is ignored on AF_INET sockets; fails on AF_INET6 sockets with WSAENOPROTOOPT. Not supported on ATM sockets (results in an error). Reserved. Sends keep-alives. Not supported on ATM sockets (results in an error). Lingers on close if unsent data is present. Receives OOB data in the normal data stream. Specifies the total per-socket buffer space reserved for receives. This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. Allows the socket to be bound to an address that is already in use. (See bind().) Not applicable on ATM sockets.

SO_EXCLUSIVEADDRUSE SO_SNDBUF PVD_CONFIG

Enables a socket to be bound for exclusive access. Does not require administrative privilege. Specifies the total per-socket buffer space reserved for sends. int This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. This object stores the configuration information for the service Service Provider provider associated with socket s. The exact format of this data Dependent structure is service provider specific. BOOL
Table 3

For level = IPPROTO_TCP1


Value Type Meaning

TCP_NODELAY BOOL 1 1.1

Disables the Nagle algorithm for send coalescing. included for backward compatibility with Windows Sockets
Table 4

For level = NSPROTO_IPX Windows NT supports all IPX options. Windows Me/98/95 supports only the following options: IPX_PTYPE IPX_FILTERPTYPE IPX_DSTYPE IPX_RECVHDR IPX_MAXSIZE (used with the getsockopt() function) IPX_ADDRESS (used with the getsockopt() function)
Value Type Meaning

IPX_PTYPE IPX_FILTERPTYPE IPX_STOPFILTERPTYPE IPX_DSTYPE IPX_EXTENDED_ADDRESS IPX_RECVHDR

int int int int BOOL BOOL

IPX_RECEIVE_BROADCAST BOOL

IPX_IMMEDIATESPXACK

BOOL

Sets the IPX packet type. Sets the receive filter packet type Stops filtering the filter type set with IPX_FILTERTYPE Sets the value of the data stream field in the SPX header on every packet sent. Sets whether extended addressing is enabled. Sets whether the protocol header is sent up on all receive headers. Indicates broadcast packets are likely on the socket. Set to TRUE by default. Applications that do not use broadcasts should set this to FALSE for better system performance. Directs SPX connections not to delay before sending an ACK. Applications without back-and-forth traffic should set this to TRUE to increase performance.
Table 5

BSD options not supported for setsockopt are shown in the following table.
Value Type Meaning

SO_ACCEPTCONN BOOL SO_RCVLOWAT int SO_RCVTIMEO SO_SNDLOWAT SO_SNDTIMEO SO_TYPE int int int int

Socket is listening. Receives low watermark. Receives time-out in milliseconds (available in the Microsoft implementation of Windows Sockets 2). Sends low watermark. Sends time-out in milliseconds (available in the Microsoft implementation of Windows Sockets 2). Type of the socket.
Table 6

SO_CONDITIONAL_ACCEPT Setting this socket option to TRUE delays the acknowledgment of a connection until after the WSAAccept() condition function is called. If FALSE, the connection may be accepted before the condition function is called, but the connection will be disconnected if the condition function rejects the call. This option must be set before calling the listen() function, otherwise WSAEINVAL is returned. SO_CONDITIONAL_ACCEPT is only supported for TCP and ATM. TCP sets SO_CONDITIONAL_ACCEPT to FALSE by default, and therefore by default the connection will be accepted before the WSAAccept() condition function is called. When set to TRUE, the conditional decision must be made within the TCP connection time-out. CF_DEFER connections are still subject to the time-out. ATM sets SO_CONDITIONAL_ACCEPT to TRUE by default. SO_DEBUG Windows Sockets service providers are encouraged (but not required) to supply output debug information if the SO_DEBUG option is set by an application. The mechanism for generating the debug information and the form it takes are beyond the scope of this document. SO_GROUP_PRIORITY Reserved for future use with socket groups. Group priority indicates the relative priority of the specified socket relative to other sockets within the socket group. Values are nonnegative integers, with zero corresponding to the highest priority. Priority values represent a hint to the underlying service provider about how potentially scarce resources should be allocated. For example, whenever two or more sockets are both ready to transmit data, the highest priority socket (lowest value for SO_GROUP_PRIORITY) should be serviced first with the remainder serviced in turn according to their relative priorities. SO_KEEPALIVE An application can request that a TCP/IP provider enable the use of keep-alive packets on TCP connections by turning on the SO_KEEPALIVE socket option. A Windows Sockets provider need not support the use of keep-alives. If it does, the precise semantics are implementation-specific but should conform to section 4.2.3.6 of RFC 1122: Requirements for Internet Hosts Communication Layers. If a connection is dropped as the result of keep-alives the error code WSAENETRESET is returned to any calls in progress on the socket, and any subsequent calls will fail with WSAENOTCONN. SO_LINGER The SO_LINGER option controls the action taken when unsent data is queued on a socket and a closesocket() is performed. See closesocket for a description of the way in which the SO_LINGER settings affect the semantics of closesocket. The application sets the desired behavior by creating a LINGER structure (pointed to by the optval parameter) with these members l_onoff and l_linger set appropriately. SO_REUSEADDR By default, a socket cannot be bound (see bind()) to a local address that is already in use. On occasion, however, it can be necessary to reuse an address in this way. Since every connection is uniquely identified by the combination of local and remote addresses, there is no problem with having two sockets bound to the same local address as long as the remote addresses are different. To inform the Windows Sockets provider that a bind on a socket should not be disallowed because the desired address is already in use by another socket, the application should set the SO_REUSEADDR socket option for the socket before issuing the bind(). The option is interpreted only at the time of the bind(). It is therefore unnecessary and harmless to set the option on a socket that is not to be bound to an existing address. Setting or resetting the option after the bind has no effect on this or any other socket. SO_RCVBUF and SO_SNDBUF When a Windows Sockets implementation supports the SO_RCVBUF and SO_SNDBUF options, an application can request different buffer sizes (larger or smaller). The call to setsockopt() can succeed even when the implementation did not provide the whole amount requested. An application must call getsockopt with the same option to check the buffer size actually provided. SO_RCVTIMEO and SO_SNDTIMEO When using the recv() function, if no data arrives during the period specified in SO_RCVTIMEO, the recv() function completes. In Windows versions prior to Windows 2000, any data received subsequently fails with WSAETIMEDOUT. In Windows 2000 and later, if no data arrives within the period specified in SO_RCVTIMEO the recv function returns WSAETIMEDOUT, and if data is received, recv returns SUCCESS. If a send or receive operation times out on a socket, the socket state is indeterminate, and should not be used; TCP sockets in this state have a potential for data loss, since the operation could be canceled at the same moment the operation was to be completed. PVD_CONFIG This object stores the configuration information for the service provider associated with the socket specified in the s parameter. The exact format of this data structure is specific to each service provider. TCP_NODELAY The TCP_NODELAY option is specific to TCP/IP service providers. The Nagle algorithm is disabled if the TCP_NODELAY option is enabled (and vice versa). The process involves buffering send data when there is unacknowledged data already in

flight or buffering send data until a full-size packet can be sent. It is highly recommended that TCP/IP service providers enable the Nagle Algorithm by default, and for the vast majority of application protocols the Nagle Algorithm can deliver significant performance enhancements. However, for some applications this algorithm can impede performance, and TCP_NODELAY can be used to turn it off. These are applications where many small messages are sent, and the time delays between the messages are maintained. Application writers should not set TCP_NODELAY unless the impact of doing so is well-understood and desired because setting TCP_NODELAY can have a significant negative impact on network and application performance.
Program Example

The following example demonstrates the setsockopt() function.


#include <stdio.h> #include <winsock2.h> void main() { // Declare variables WSADATA wsaData; SOCKET ListenSocket; sockaddr_in service; // Initialize Winsock, request the Winsock 2.2 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if(iResult != NO_ERROR) printf("Error at WSAStartup().\n"); else printf("WSAStartup() is OK.\n"); // Create a listening socket ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("Error at socket().\n"); WSACleanup(); return; } else printf("socket() is OK.\n"); // Bind the socket to the local IP address and port 55555 hostent* thisHost; char* ip; u_short port; port = 55555; thisHost = gethostbyname(""); ip = inet_ntoa(*(struct in_addr *)*thisHost->h_addr_list); // Try running this program on machine using live IP... printf("\nIP address is: %s.\n", ip); printf("Hostname is: %s.\n", thisHost->h_name); printf("Address type: %i.\n\n", thisHost->h_addrtype); service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(ip); service.sin_port = htons(port); if (bind(ListenSocket,(SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) { printf("bind() failed lol!\n"); closesocket(ListenSocket); return; } else printf("bind() is OK.\n"); // Initialize variables and call setsockopt(). // The SO_KEEPALIVE parameter is a socket option // that makes the socket send keepalive messages // on the session. The SO_KEEPALIVE socket option // requires a boolean value to be passed to the // setsockopt function. If TRUE, the socket is // configured to send keepalive messages, if FALSE // the socket configured to NOT send keepalive messages. // This section of code tests the setsockopt() function // by checking the status of SO_KEEPALIVE on the socket // using the getsockopt() function. BOOL bOptVal = TRUE; int bOptLen = sizeof(BOOL); int iOptVal; int iOptLen = sizeof(int);

if (getsockopt(ListenSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) { printf("SO_KEEPALIVE value: %ld.\n", iOptVal); } if (setsockopt(ListenSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, bOptLen) != SOCKET_ERROR) { printf("Sends keep-alives. Setting the SO_KEEPALIVE.\n"); } if (getsockopt(ListenSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) { printf("SO_KEEPALIVE value: %ld.\n", iOptVal); } // Binding to the already used socket BOOL bOptVal1 = TRUE; int bOptLen1 = sizeof(BOOL); int iOptVal1; int iOptLen1 = sizeof(int); if (setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal1, bOptLen1) != SOCKET_ERROR) { printf("Socket can be bound to an address that is already in use.\n"); } if (getsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&iOptVal1, &iOptLen1) != SOCKET_ERROR) { printf("SO_REUSEADDR value: %ld.\n", iOptVal1); } WSACleanup(); return; }

Figure 1 For IrDA Sockets keep in mind the following: The af_irda.h header file must be explicitly included. IrDA provides the following settable socket option:
Value Type Meaning

IRLMP_IAS_SET *IAS_SET
Table 7

Sets IAS attributes

The IRLMP_IAS_SET socket option enables the application to set a single attribute of a single class in the local Internet Authentication Service (IAS). The application specifies the class to set, the attribute, and attribute type. The application is expected to allocate a buffer of the necessary size for the passed parameters. IrDA provides an IAS database that stores IrDAbased information. Limited access to the IAS database is available through the Windows Sockets 2 interface, but such access is not normally used by applications, and exists primarily to support connections to non-Windows devices that are not compliant with the Windows Sockets 2 IrDA conventions. The following structure, IAS_SET, is used with the IRLMP_IAS_SET setsockopt() option to manage the local IAS database:
typedef struct _IAS_SET {

char char u_long union {

irdaClassName[IAS_MAX_CLASSNAME]; irdaAttribName[IAS_MAX_ATTRIBNAME]; irdaAttribType;

LONG irdaAttribInt; struct { u_short Len; u_char OctetSeq[IAS_MAX_OCTET_STRING]; } irdaAttribOctetSeq; struct { u_char Len; u_char CharSet; u_char UsrStr[IAS_MAX_USER_STRING]; } irdaAttribUsrStr; } irdaAttribute; } IAS_SET, *PIAS_SET, FAR *LPIAS_SET;

The following structure, IAS_QUERY, is used with the IRLMP_IAS_QUERY setsockopt() option to query a peer's IAS database:
typedef struct _WINDOWS_IAS_QUERY { u_char irdaDeviceID[4]; char irdaClassName[IAS_MAX_CLASSNAME]; char irdaAttribName[IAS_MAX_ATTRIBNAME]; u_long irdaAttribType; union { LONG irdaAttribInt; struct { u_long Len; u_char OctetSeq[IAS_MAX_OCTET_STRING]; } irdaAttribOctetSeq; struct { u_long Len; u_long CharSet; u_char UsrStr[IAS_MAX_USER_STRING]; } irdaAttribUsrStr; } irdaAttribute; } IAS_QUERY, *PIAS_QUERY, FAR *LPIAS_QUERY;

Many SO_ level socket options are not meaningful to IrDA. Only SO_LINGER is specifically supported. WINDOWS SOCKET: PROGRAM EXAMPLES PART 7 getsockopt()
Item Description

Function Use

getsockopt(). Retrieves a socket option.


int getsockopt( SOCKET s, int level, int optname, char* optval, int* optlen);

Prototype

Parameters

s [in] Descriptor identifying a socket. level [in] Level at which the option is defined. Example: SOL_SOCKET. optname [in] Socket option for which the value is to be retrieved. Example: SO_ACCEPTCONN. The optname value must be a socket option defined within the specified level, or behavior is undefined.

optval [out] Pointer to the buffer in which the value for the requested option is to be returned. optlen [in, out] Pointer to the size of the optval buffer, in bytes. Return value See below. Include file <winsock2.h> ws2_32.lib. Library Remark See below.
Table 1 Return Values

If no error occurs, getsockopt() returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

A successful WSAStartup() call must occur before using this WSANOTINITIALISED function. WSAENETDOWN The network subsystem has failed. One of the optval or the optlen parameters is not a valid part of the WSAEFAULT user address space, or the optlen parameter is too small. A blocking Windows Sockets 1.1 call is in progress, or the service WSAEINPROGRESS provider is still processing a callback function. WSAEINVAL The level parameter is unknown or invalid. WSAENOPROTOOPT The option is unknown or unsupported by the indicated protocol family. WSAENOTSOCK The descriptor is not a socket.
Table 2 Remarks

The getsockopt() function retrieves the current value for a socket option associated with a socket of any type, in any state, and stores the result in optval. Options can exist at multiple protocol levels, but they are always present at the uppermost socket level. Options affect socket operations, such as the packet routing and OOB data transfer. The value associated with the selected option is returned in the buffer optval. The integer pointed to by optlen should originally contain the size of this buffer; on return, it will be set to the size of the value returned. For SO_LINGER, this will be the size of a LINGER structure. For most other options, it will be the size of an integer. The application is responsible for allocating any memory space pointed to directly or indirectly by any of the parameters it specified. If the option was never set with setsockopt(), then getsockopt() returns the default value for the option. The following options are supported for getsockopt(). The Type column identifies the type of data addressed by optval. For level = SOL_SOCKET
Value Type Meaning

SO_ACCEPTCONN SO_BROADCAST

BOOL BOOL

SO_CONDITIONAL_ACCEPT BOOL SO_DEBUG SO_DONTLINGER SO_DONTROUTE SO_ERROR SO_GROUP_ID SO_GROUP_PRIORITY SO_KEEPALIVE SO_LINGER BOOL BOOL BOOL int GROUP int BOOL LINGER structure

Socket is listening. Socket is configured for the transmission and receipt of broadcast messages. Returns current socket state, either from a previous call to setsockopt() or the system default. Debugging is enabled. If TRUE, the SO_LINGER option is disabled. Routing is disabled. Succeeds but is ignored on AF_INET sockets; fails on AF_INET6 sockets with WSAENOPROTOOPT. Not supported on ATM sockets. Retrieves error status and clear. Reserved. Reserved. Keep-alives are being sent. Not supported on ATM sockets. Returns the current linger options.

SO_MAX_MSG_SIZE SO_OOBINLINE SO_PROTOCOL_INFO SO_RCVBUF SO_REUSEADDR SO_SNDBUF SO_TYPE PVD_CONFIG

unsigned int BOOL WSAPROTOCOL_INFO int BOOL int int Service Provider Dependent

Maximum size of a message for message-oriented socket types (for example, SOCK_DGRAM). Has no meaning for stream oriented sockets. OOB data is being received in the normal data stream. Description of protocol information for protocol that is bound to this socket. Buffer size for receives. The socket can be bound to an address which is already in use. Not applicable for ATM sockets. Buffer size for sends. The type of the socket (for example, SOCK_STREAM). An opaque data structure object from the service provider associated with socket s. This object stores the current configuration information of the service provider. The exact format of this data structure is service provider specific.

Table 3

For level = IPPROTO_TCP


Value Type Meaning

TCP_NODELAY

BOOL

Disables the Nagle algorithm for send coalescing.


Table 4

For level = NSPROTO_IPX Windows NT supports all IPX options. Windows Me/98/95 supports only the following options: IPX_PTYPE IPX_FILTERPTYPE IPX_DSTYPE IPX_RECVHDR IPX_MAXSIZE IPX_ADDRESS
Value Type Meaning

IPX_PTYPE IPX_FILTERPTYPE IPX_DSTYPE IPX_EXTENDED_ADDRESS IPX_RECVHDR IPX_MAXSIZE

int int int BOOL BOOL int

IPX_ADDRESS

IPX_ADDRESS_DATA structure

IPX_GETNETINFO

IPX_NETNUM_DATA structure

IPX_GETNETINFO_NORIP IPX_SPXGETCONNECTIONSTATUS

IPX_NETNUM_DATA structure IPX_SPXCONNSTATUS_DATA structure

Retrieves the IPX packet type. Retrieves the receive filter packet type Obtains the value of the data stream field in the SPX header on every packet sent. Finds out whether extended addressing is enabled. Finds out whether the protocol header is sent up on all receive headers. Obtains the maximum data size that can be sent. Obtains information about a specific adapter to which IPX is bound. Adapter numbering is base zero. The adapternum member is filled in upon return. Obtains information about a specific IPX network number. If not available in the cache, uses RIP to obtain information. Obtains information about a specific IPX network number. If not available in the cache, will not use RIP to obtain information, and returns error. Retrieves information about a connected SPX socket.

IPX_ADDRESS_NOTIFY IPX_MAX_ADAPTER_NUM

IPX_ADDRESS_DATA structure int

IPX_RERIPNETNUMBER

IPX_NETNUM_DATA structure

IPX_IMMEDIATESPXACK

BOOL

Retrieves status notification when changes occur on an adapter to which IPX is bound. Retrieves maximum number of adapters present, numbered as base zero. Similar to IPX_GETNETINFO, but forces IPX to use RIP for resolution, even if the network information is in the local cache. Directs SPX connections not to delay before sending an ACK. Applications without back-and-forth traffic should set this to TRUE to increase performance.

Table 5

BSD options not supported for getsockopt() are as shown in the following table.
Value Type Meaning

SO_RCVLOWAT SO_RCVTIMEO SO_SNDLOWAT SO_SNDTIMEO TCP_MAXSEG

int int int int int

Receives low watermark. Receives time-out. Sends low watermark. Sends time-out. Receives TCP maximumsegment size.
Table 6

When using the recv() function, if no data arrives during the period specified in SO_RCVTIMEO, the recv() function completes. In Windows versions prior to Windows 2000, any data received subsequently fails with WSAETIMEDOUT. In Windows 2000 and later, if no data arrives within the period specified in SO_RCVTIMEO the recv() function returns WSAETIMEDOUT, and if data is received, recv() returns SUCCESS. Calling getsockopt() with an unsupported option will result in an error code of WSAENOPROTOOPT being returned from WSAGetLastError(). SO_DEBUG Windows Sockets service providers are encouraged (but not required) to supply output debug information if the SO_DEBUG option is set by an application. The mechanism for generating the debug information and the form it takes are beyond the scope of this document. SO_ERROR The SO_ERROR option returns and resets the per socketbased error code, which is different from the per thread basederror code that is handled using the WSAGetLastError() and WSASetLastError() function calls. A successful call using the socket does not reset the socket based error code returned by the SO_ERROR option. SO_GROUP_ID This option is reserved. This option is also exclusive to getsockopt(); the value should be null. SO_GROUP_PRIORITY This option is reserved. Group priority indicates the priority of the specified socket relative to other sockets within the socket group. Values are nonnegative integers, with zero corresponding to the highest priority. Priority values represent a hint to the underlying service provider about how potentially scarce resources should be allocated. For example, whenever two or more sockets are both ready to transmit data, the highest priority socket (lowest value for SO_GROUP_PRIORITY) should be serviced first, with the remainder serviced in turn according to their relative priorities. The WSAENOPROTOOPT error code is indicated for non-group sockets or for service providers that do not support group sockets. SO_KEEPALIVE An application can request that a TCP/IP service provider enable the use of keep-alive packets on TCP connections by turning on the SO_KEEPALIVE socket option. A Windows Sockets provider need not support the use of keep-alive: if it does, the precise semantics are implementation-specific but should conform to section 4.2.3.6 of RFC 1122: Requirements for Internet Hosts - Communication Layers. If a connection is dropped as the result of keep-alives the error code WSAENETRESET is returned to any calls in progress on the socket, and any subsequent calls will fail with WSAENOTCONN. SO_KEEPALIVE is

not supported on ATM sockets, and requests to enable the use of keep-alive packets on an ATM socket results in an error being returned by the socket. SO_LINGER SO_LINGER controls the action taken when unsent data is queued on a socket and a closesocket() is performed. See closesocket() for a description of the way in which the SO_LINGER settings affect the semantics of closesocket(). The application gets the current behavior by retrieving a LINGER structure (pointed to by the optval parameter). SO_MAX_MSG_SIZE This is a get-only socket option that indicates the maximum outbound (send) size of a message for message-oriented socket types (for example, SOCK_DGRAM) as implemented by a particular service provider. It has no meaning for byte stream oriented sockets. There is no provision to find out the maximum inboundmessage size. SO_PROTOCOL_INFO This is a get-only option that supplies the WSAPROTOCOL_INFO structure associated with this socket. SO_SNDBUF When a Windows Sockets implementation supports the SO_RCVBUF and SO_SNDBUF options, an application can request different buffer sizes (larger or smaller). The call to setsockopt() can succeed even if the implementation did not provide the whole amount requested. An application must call this function with the same option to check the buffer size actually provided. SO_REUSEADDR By default, a socket cannot be bound (see bind()) to a local address that is already in use. On occasion, however, it can be necessary to reuse an address in this way. Because every connection is uniquely identified by the combination of local and remote addresses, there is no problem with having two sockets bound to the same local address as long as the remote addresses are different. To inform the Windows Sockets provider that a bind on a socket should not be disallowed because the desired address is already in use by another socket, the application should set the SO_REUSEADDR socket option for the socket before issuing the bind. Note that the option is interpreted only at the time of the bind(): it is therefore unnecessary (but harmless) to set the option on a socket that is not to be bound to an existing address, and setting or resetting the option after the bind() has no effect on this or any other socket. SO_REUSEADDR is not applicable for ATM sockets, and although requests to reuse and address do not result in an error, they have no affect on when an ATM socket is in use. PVD_CONFIG This option retrieves an opaque data structure object from the service provider associated with socket s. This object stores the current configuration information of the service provider. The exact format of this data structure is service provider specific. TCP_NODELAY The TCP_NODELAY option is specific to TCP/IP service providers. The Nagle algorithm is disabled if the TCP_NODELAY option is enabled (and vice versa). The Nagle algorithm (described in RFC 896) is very effective in reducing the number of small packets sent by a host. The process involves buffering send data when there is unacknowledged data already in flight or buffering send data until a full-size packet can be sent. It is highly recommended that Windows Sockets implementations enable the Nagle Algorithm by default because, for the vast majority of application protocols, the Nagle Algorithm can deliver significant performance enhancements. However, for some applications this algorithm can impede performance and setsockopt() with the same option can be used to turn it off. These are applications where many small messages are sent, and the time delays between the messages are maintained.
Program Example

The following code sample demonstrates the use of the getsockopt() function.
#include <stdio.h> #include "winsock2.h" void main() { // Declare variables WSADATA wsaData; SOCKET ListenSocket; sockaddr_in service; // Initialize Winsock, request Winsock 2.2 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if(iResult != NO_ERROR) printf("Error at WSAStartup().\n"); else printf("WSAStartup() is OK.\n"); // Create a listening socket

ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("Error at socket()\n"); WSACleanup(); return; } else printf("socket() is OK.\n"); // Bind the socket to the local IP address and port 55555 hostent* thisHost; char* ip; u_short port; port = 55555; thisHost = gethostbyname(""); ip = inet_ntoa(*(struct in_addr *)*thisHost->h_addr_list); // Try running this program on machine using live IP... printf("\nIP address is: %s.\n", ip); printf("Hostname is: %s.\n", thisHost->h_name); printf("Address type: %i.\n\n", thisHost->h_addrtype); service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(ip); service.sin_port = htons(port); if (bind(ListenSocket,(SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) { printf("bind() failed.\n"); closesocket(ListenSocket); return; } else printf("bind() is OK.\n"); // Initialize variables and call getsockopt(). // The SO_ACCEPTCONN parameter is a socket option // that tells the function to check whether the // socket has been put in listening mode or not. // The various socket options return different // information about the socket. This call should // return 0 to the optVal parameter, since the socket // is not in listening mode. int optVal; int optLen = sizeof(int); if (getsockopt(ListenSocket, SOL_SOCKET, SO_ACCEPTCONN, (char*)&optVal, &optLen) != SOCKET_ERROR) printf("Initial SockOpt value: %ld\n", optVal); // Put the listening socket in listening mode. if (listen(ListenSocket, 100) == SOCKET_ERROR) { printf("Error listening.\n"); } else printf("listen() is OK. Socket in listening mode...\n"); // Call getsockopt() again to verify that // the socket is in listening mode. if (getsockopt(ListenSocket, SOL_SOCKET, SO_ACCEPTCONN, (char*)&optVal, &optLen) != SOCKET_ERROR) printf("Then, SockOpt value: %ld.\n", optVal); else printf("Error getsockopt().\n"); WSACleanup(); return; }

Figure 1 For IrDA Sockets: The af_irda.h header file must be explicitly included. Windows returns WSAENETDOWN to indicate the underlying transceiver driver failed to initialize with the IrDA protocol stack. IrDA supports several special socket options:
Value Type Meaning

IRLMP_ENUMDEVICES *DEVICELIST IRLMP_IAS_QUERY *IAS_QUERY


Table 7

Describes devices in range. Retrieve IAS attributes.

Before an IrDA socket connection can be initiated, a device address must be obtained by performing a getsockopt(,,IRLMP_ENUMDEVICES,,) function call, which returns a list of all available IrDA devices. A device address returned from the function call is copied into a SOCKADDR_IRDA structure, which in turn is used by a subsequent call to the connect() function call. Discovery can be performed in two ways: First, performing a getsockopt() function call with the IRLMP_ENUMDEVICES option causes a single discovery to be run on each idle adapter. The list of discovered devices and cached devices (on active adapters) is returned immediately. The following code demonstrates this approach.
SOCKADDR_IRDA DestSockAddr = {AF_IRDA, 0, 0, 0, 0, "SampleIrDAService"}; 10

#define DEVICE_LIST_LEN unsigned char int PDEVICELIST

DevListBuff[sizeof(DEVICELIST) &#8211; sizeof(IRDA_DEVICE_INFO) + (sizeof(IRDA_DEVICE_INFO) * DEVICE_LIST_LEN)]; DevListLen = sizeof(DevListBuff); pDevList = (PDEVICELIST) &DevListBuff;

pDevList->numDevice = 0; // Sock is not in connected state if (getsockopt(Sock, SOL_IRLMP, IRLMP_ENUMDEVICES, (char *) pDevList, &DevListLen) == SOCKET_ERROR) { // WSAGetLastError } if (pDevList->numDevice == 0) { // no devices discovered or cached // not a bad idea to run a couple of times } else { // one per discovered device for (i = 0; i < (int) pDevList->numDevice; i++) { // typedef struct _IRDA_DEVICE_INFO // { // u_char irdaDeviceID[4];

// char irdaDeviceName[22]; // u_char irdaDeviceHints1; // u_char irdaDeviceHints2; // u_char irdaCharSet; // } _IRDA_DEVICE_INFO; // pDevList->Device[i]. see _IRDA_DEVICE_INFO for fields // display the device names and let the user select one

} }

// assume the user selected the first device [0] memcpy(&DestSockAddr.irdaDeviceID[0], &pDevList->Device[0].irdaDeviceID[0], 4); if (connect(Sock, (const struct sockaddr *) &DestSockAddr, sizeof(SOCKADDR_IRDA)) == SOCKET_ERROR) { // WSAGetLastError }

The second approach to performing discovery of IrDA device addresses is to perform a lazy discovery; in this approach, the application is not notified until the discovered devices list changes from the last discovery run by the stack. The DEVICELIST structure shown in the Type column in the previous table is an extendible array of device descriptions. IrDA fills in as many device descriptions as can fit in the specified buffer. The device description consists of a device identifier necessary to form a sockaddr_irda structure, and a displayable string describing the device. The IAS_QUERY structure shown in the Type column in the previous table is used to retrieve a single attribute of a single class from a peer device's IAS database. The application specifies the device and class to query and the attribute and attributes type. Note that the device would have been obtained previously by a call to getsockopt(IRLMP_ENUMDEVICES). It is expected that the application allocates a buffer, of the necessary size, for the returned parameters. Many level socket options are not meaningful to IrDA; only SO_LINGER and SO_DONTLINGER are specifically supported. WINDOWS SOCKET: PROGRAM EXAMPLES PART 8 sockaddr
Item Description

Structure Info

sockaddr. Contains socket address information. The sockaddr structure varies depending on the protocol selected. It is better to use SOCKADDR_STORAGE instead.
struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; struct sockaddr_in6 { short sin6_family; u_short sin6_port; u_long sin6_flowinfo; struct in6_addr sin6_addr; u_long sin6_scope_id; }; struct sockaddr_in6_old { short sin6_family; u_short sin6_port; u_long sin6_flowinfo; struct in6_addr sin6_addr; };

Definition

Members Header file

Remark

As mentioned above. <winsock2.h> for IPv4; <ws2tcpip.h> for IPv6. The sockaddr structure varies depending on the protocol selected. Except for the sin*_family parameter, sockaddr contents are expressed in network byte order. Winsock functions using sockaddr are not strictly interpreted to be pointers to a sockaddr structure. The structure is interpreted differently in the context of different address families. The only requirements are that the first u_short is the address family and the total size of the memory buffer in bytes is namelen. Other protocols use similar structures.
Table 1

Program Example

The following example demonstrates the use of the sockaddr structure.


#include <stdio.h> #include "winsock2.h" int main() { // Declare variables WSADATA wsaData; SOCKET ListenSocket; sockaddr_in service; // Initialize Winsock, request the Winsock 2.2 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if(iResult != NO_ERROR) printf("Error at WSAStartup().\n"); else printf("WSAStartup() is OK.\n"); // Create a listening socket ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("Error at socket().\n"); WSACleanup(); return 0; } else printf("socket() is OK.\n"); // Bind the socket to the local IP address and port 55555 hostent* thisHost; char* ip; u_short port; port = 55555; thisHost = gethostbyname(""); ip = inet_ntoa(*(struct in_addr *)*thisHost->h_addr_list); printf("\nIP address is: %s.\n", ip); printf("Hostname is: %s.\n", thisHost->h_name); printf("Address type: %i.\n\n", thisHost->h_addrtype); service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(ip); service.sin_port = htons(port); if (bind(ListenSocket,(SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) { printf("bind() failed lol!\n"); closesocket(ListenSocket); return 0; } else printf("bind() is OK.\n"); WSACleanup(); return 0; }

Figure 1 hostent
Item Description

Structure hostent. Used by functions to store information about a given host, such as host name, IP address, and so forth. An application should never attempt to modify this structure or to free any Info of its components. Furthermore, only one copy of the hostent structure is allocated per thread, and an application should therefore copy any information that it needs before issuing any other Windows Sockets API calls.
typedef struct hostent { char FAR* h_name; char FAR FAR** h_aliases; short h_addrtype; Definition short h_length; char FAR FAR** h_addr_list; } hostent;

h_name Official name of the host (PC). If using the DNS or similar resolution system, it is the Fully Qualified Domain Name (FQDN) that caused the server to return a reply. If using a local hosts file, it is the first entry after the IP address. h_aliases Null-terminated array of alternate names. Members h_addrtype Type of address being returned. h_length Length of each address, in bytes. h_addr_list Null-terminated list of addresses for the host. Addresses are returned in network byte order. The macro h_addr is defined to be h_addr_list[0] for compatibility with older software. Header file Remark <winsock2.h> Table 2

gethostbyaddr()
Item Description

Function

Use

gethostbyaddr(). Retrieves the host information corresponding to a network address. The gethostbyaddr function has been deprecated by the introduction of the getnameinfo() function. Developers creating Windows Sockets 2 applications are urged to use the getnameinfo function instead of the gethostbyaddr() function.
struct HOSTENT* FAR gethostbyaddr( const char* addr, int len, int type);

Prototype

addr [in] Pointer to an address in network byte order. len [in] Length of the address, in bytes.

Parameters

type [in] Type of the address, such as the AF_INET address family type (defined as TCP, UDP, and other associated Internet protocols). Address family types and their corresponding values are defined in the winsock2.h header file. Return value See below. Include file <winsock2.h> ws2_32.lib. Library Remark The gethostbyaddr() function returns a pointer to the hostent structure that contains the name and address corresponding to the given network address. Although gethostbyaddr is deprecated by the getnameinfo() function, gethostbyaddr is capable of returning a NetBIOS name; getnameinfo is not.

Developers requiring NetBIOS name resolution may need to use gethostbyaddr() until their applications are completely independent of NetBIOS names. Note The capability to perform reverse lookups using the gethostbyaddr function is convenient, but such lookups are considered inherently unreliable, and should be used only as a hint.
Table 3 Return Values

If no error occurs, gethostbyaddr() returns a pointer to the hostent structure. Otherwise, it returns a null pointer, and a specific error code can be retrieved by calling WSAGetLastError().
Error code Meaning

A successful WSAStartup() call must occur before using this WSANOTINITIALISED function. WSAENETDOWN The network subsystem has failed. WSAHOST_NOT_FOUND Authoritative answer host not found. WSATRY_AGAIN Non-authoritative host not found, or server failed. WSANO_RECOVERY A non-recoverable error occurred. WSANO_DATA Valid name, no data record of requested type. A blocking Windows Sockets 1.1 call is in progress, or the service WSAEINPROGRESS provider is still processing a callback function. The type specified is not supported by the Windows Sockets WSAEAFNOSUPPORT implementation. The addr parameter is not a valid part of the user address space, or the WSAEFAULT len parameter is too small. A blocking Windows Socket 1.1 call was canceled through WSAEINTR WSACancelBlockingCall().
Table 4

For program sample, see the following example. gethostbyname()


Item Description

Function Use Prototype Parameters

gethostbyname(). Retrieves host information corresponding to a host name from a host database. The gethostbyname() function has been deprecated by the introduction of the getaddrinfo() function. Developers creating Windows Sockets 2 applications are urged to use the getaddrinfo() function instead of gethostbyname().
struct hostent* FAR gethostbyname(const char* name);

name [in] Pointer to the null-terminated name of the host to resolve. Return value See below. Include file <winsock2.h> ws2_32.lib. Library The gethostbyname() function returns a pointer to a hostent structure - a structure allocated by Windows Sockets. The hostent structure contains the results of a successful search for the host specified in the name parameter. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, so the application should copy any information it needs before issuing any other Windows Sockets function calls. The gethostbyname() function cannot resolve IP address strings passed to it. Remark Such a request is treated exactly as if an unknown host name were passed. Use inet_addr to convert an IP address string the string to an actual IP address, then use another function, gethostbyaddr(), to obtain the contents of the hostent structure. If null is provided in the name parameter, the returned string is the same as the string returned by a successful gethostname() function call. The gethostbyname() function does not check the size of the name parameter before passing the buffer. In improperly sized name parameters, heap corruption can occur.

Table 5 Return Values

If no error occurs, gethostbyname() returns a pointer to the hostent structure described above. Otherwise, it returns a null pointer and a specific error number can be retrieved by calling WSAGetLastError().
Error code Meaning

A successful WSAStartup() call must occur before using this WSANOTINITIALISED function. WSAENETDOWN The network subsystem has failed. WSAHOST_NOT_FOUND Authoritative answer host not found. WSATRY_AGAIN Non-authoritative host not found, or server failure. WSANO_RECOVERY A non-recoverable error occurred. WSANO_DATA Valid name, no data record of requested type. A blocking Windows Sockets 1.1 call is in progress, or the service WSAEINPROGRESS provider is still processing a callback function. WSAEFAULT The name parameter is not a valid part of the user address space. A blocking Windows Socket 1.1 call was canceled through WSAEINTR WSACancelBlockingCall().
Table 6 Program Example

The following examples demonstrates the use of the gethostbyname() and gethostbyaddr() functions.
#include <stdio.h> #include <winsock2.h> int main() { // Declare variables WSADATA wsaData; // Initialize Winsock, request the Winsock 2.2 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if(iResult != NO_ERROR) printf("Error at WSAStartup().\n"); else printf("WSAStartup() is OK.\n"); // Declare and initialize variables hostent* remoteHost; char* ip; char* host_name; unsigned int addr; // User inputs name of host printf("Input name/IP of host: "); host_name = (char*) malloc(sizeof(char*)*128); fgets(host_name, 128, stdin); // // // if { If the user input is an alpha name for the host, use gethostbyname() else, gethostbyaddr() (assume IPv4) host address is a name (isalpha(host_name[0])) printf("\nUsing gethostbyname()...\n"); // NULL terminated host_name[strlen(host_name)-1] = '\0'; remoteHost = gethostbyname(host_name); ip = inet_ntoa(*(struct in_addr *)*remoteHost->h_addr_list); printf("IP address is: %s.\n", ip); printf("Address type: %i.\n\n", remoteHost->h_addrtype);

} else { printf("\nUsing gethostbyaddr()...\n"); addr = inet_addr(host_name); remoteHost = gethostbyaddr((char *)&addr, 4, AF_INET); printf("Hostname is: %s.\n", remoteHost->h_name); printf("Address type: %i.\n\n", remoteHost->h_addrtype); } if (WSAGetLastError() != 0)

{ if (WSAGetLastError() == 11001) printf("Host not found...\nExiting.\n"); } else printf("error #: %ld\n", WSAGetLastError()); // The remoteHost structure can now be used to // access information about the host WSACleanup(); return 0;

Figure 2

Figure 3 WINDOWS SOCKET: PROGRAM EXAMPLES PART 9 getnameinfo()


Item Description

Function Use

getnameinfo(). Provides name resolution from an address to the host name.


int getnameinfo( const struct sockaddr* sa, socklen_t salen, char* host, DWORD hostlen, char* serv, DWORD servlen, int flags);

Prototype

Parameters

sa [in] Pointer to a socket address structure containing the address and port number of the socket. For IPv4, the sa parameter points to a sockaddr_in structure; for IPv6, the sa parameter points to a sockaddr_in6 structure. salen [in] Length of the structure pointed to in the sa parameter, in bytes. host [out] Pointer to the host name. The host name is returned as a Fully Qualified Domain Name (FQDN) by default. hostlen [in] Length of the buffer pointed to by the host parameter, in bytes. The caller

must provide a buffer large enough to hold the host name, including terminating NULL characters. A value of zero indicates the caller does not want to receive the string provided in host. serv [out] Pointer to the service name associated with the port number. servlen [in] Length of the buffer pointed to by the serv parameter, in bytes. The caller must provide a buffer large enough to hold the service name, including terminating null characters. A value of zero indicates the caller does not want to receive the string provided in serv. flags [in] Flags used to customize processing of the getnameinfo() function. Success returns zero. Any nonzero return value indicates failure. Use the Return value WSAGetLastError() function to retrieve error information. Include file <winsock2.h >, <ws2tcpip.h> Library Declared in ws2tcpip.h; include <wspiapi.h> for Windows 95/98/Me, Remark Windows 2000 and Windows NT.
Table 1 Remarks

To simplify determining buffer requirements for the host and serv parameters, the following values for maximum host name length and maximum service name are defined in the ws2tcpip.h header file:
#define NI_MAXHOST #define NI_MAXSERV 1025 32

The flags parameter can be used to customize processing of the getnameinfo function. The following flags are available: NI_NOFQDN NI_NUMERICHOST NI_NAMEREQD NI_NUMERICSERV NI_DGRAM

When the NI_NAMEREQD flag is set, host names that cannot be resolved by Domain Name System (DNS) result in an error. Setting the NI_NOFQDN flag results in local hosts having only their Relative Distinguished Name (RDN) returned in the host parameter. Setting the NI_NUMERICHOST flag returns the numeric form of the host name instead of its name. The numeric form of the host name is also returned if the host name cannot be resolved by DNS. Setting the NI_NUMERICSERV flag returns the port number of the service instead of its name. If NI_NUMERICSERV is not specified and the port number contained in sa does not resolve to a well known service, the getnameinfo() function fails. When NI_NUMERICSERV is specified, the port number is returned as a numeric string. Setting the NI_DGRAM flag indicates that the service is a datagram service. This flag is necessary for the few services that provide different port numbers for UDP and TCP service. The capability to perform reverse lookups using the getnameinfo() function is convenient, but such lookups are considered inherently unreliable, and should be used only as a hint. Macros in the Winsock header file define the mixed-case function name GetNameInfo() to getnameinfo(); either spelling is acceptable.
Program Example

The following example demonstrates the use of the getnameinfo() function.


// Run on Windows Xp Pro, Visual C++ .Net 1.1 #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #define NI_MAXHOST 1025 #define NI_MAXSERV 32 int main() { // Declare variables WSADATA wsaData;

// Initialize Winsock, request the Winsock 2.2 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if(iResult != NO_ERROR) printf("Error at WSAStartup().\n"); else printf("WSAStartup() is OK.\n"); // Declare and initialize variables hostent* remoteHost; char* ip; struct sockaddr_in saGNI; char *hostName; char servInfo[256]; int retVal; u_short port; port = 55555; // Input name of host printf("Input name of host: "); hostName = (char*) malloc(sizeof(char*)*128); fgets(hostName, 128, stdin); printf("\nUsing gethostbyname()...\n"); hostName[strlen(hostName)-1] = '\0'; remoteHost = gethostbyname(hostName); ip = inet_ntoa(*(struct in_addr *)*remoteHost->h_addr_list); printf("IP address is: %s.\n", ip); printf("Address type: %i.\n\n", remoteHost->h_addrtype); // Set up sockaddr_in structure which is passed // to the getnameinfo() function saGNI.sin_family = AF_INET; // saGNI.sin_addr.s_addr = inet_addr(ip); saGNI.sin_addr.s_addr = inet_addr(ip); saGNI.sin_port = htons(port); // Call getnameinfo if ((retVal = getnameinfo((SOCKADDR *)&saGNI, sizeof(sockaddr), hostName, 256, servInfo, 256, NI_NUMERICSERV)) != 0) { printf("getnameinfo() failed.\n"); printf("Error #: %ld.\n", WSAGetLastError()); } else printf("getnameinfo() is OK.\n"); WSACleanup(); return 0;

Figure 1 getaddrinfo()
Item Description

Function Use Prototype

getaddrinfo(). Provides protocol-independent translation from host name to address.


int getaddrinfo( const char* nodename, const char* servname,

const struct addrinfo* hints, struct addrinfo** res);

nodename [in] Pointer to a null-terminated string containing a host (node) name or a numeric host address string. The numeric host address string is a dotted-decimal IPv4 address or an IPv6 hex address. servname [in] Pointer to a null-terminated string containing either a service name or port number. hints [in] Pointer to an addrinfo structure that provides hints about the type of socket the caller supports. res [out] Pointer to a linked list of one or more addrinfo structures containing response information about the host. Return value Include file <winsock2.h>, <ws2tcpip.h> ws2_32.lib. Library Include <wspiapi.h> for Windows 95/98/Me, Windows 2000 and Windows NT. Remark
Table 2 Return Values

Parameters

Success returns zero. Failure returns a nonzero Windows Sockets error code, as found in the Windows Sockets Error Codes. Nonzero error codes returned by the getaddrinfo() function also map to the set of errors outlined by IETF recommendations. The following table shows these error codes and their WSA* equivalents. It is recommended that the WSA* error codes be used, as they offer familiar and comprehensive error information for Winsock programmers.
Error value WSA* equivalent Description

EAI_AGAIN EAI_BADFLAGS EAI_FAIL EAI_FAMILY EAI_MEMORY EAI_NODATA EAI_NONAME EAI_SERVICE

WSATRY_AGAIN WSAEINVAL WSANO_RECOVERY WSAEAFNOSUPPORT WSA_NOT_ENOUGH_MEMORY WSANO_DATA WSAHOST_NOT_FOUND WSATYPE_NOT_FOUND

EAI_SOCKTYPE WSAESOCKTNOSUPPORT
Table 3

Temporary failure in name resolution. Invalid value for ai_flags. Non-recoverable failure in name resolution. The ai_family member is not supported. Memory allocation failure. No address associated with nodename. Neither nodename nor servname provided, or not known. The servname parameter is not supported for ai_socktype. The ai_socktype member is not supported.

You can use the gai_strerror() function to print error messages based on the EAI_* codes returned by the getaddrinfo() function. The gai_strerror() function is provided for compliance with IETF recommendations, but it is not thread safe. Therefore, use of traditional Windows Sockets functions such as WSAGetLastError() is recommended.
Remarks

One or both of the nodename or servname parameters must point to a NULL-terminated string; generally both are provided. Upon success, a linked list of addrinfo structures is returned in the res parameter; the list can be processed by following the pointer provided in the ai_next member of each returned addrinfo structure until a null pointer is encountered. In each returned addrinfo structure, the ai_family, ai_socktype, and ai_protocol members correspond to respective arguments in a socket() function call. Also, the ai_addr member in each returned addrinfo structure points to a filled-in socket address structure, the length of which is specified in its ai_addrlen member. If nodename is a machine name, machine permanent addresses are returned. If nodename contains the string "..localmachine", all registered addresses are returned. If nodename refers to a cluster virtual server name, only virtual server addresses are returned. Callers of the getaddrinfo() function can provide hints about the type of socket supported through an addrinfo structure pointed to by the hints parameter. When the hints parameter is used, the following rules apply to its associated addrinfo structure:

A value of PF_UNSPEC for ai_family indicates the caller will accept any protocol family. A value of zero for ai_socktype indicates the caller will accept any socket type. A value of zero for ai_protocol indicates the caller will accept any protocol. ai_addrlen must be zero or a null pointer. ai_canonname must be zero or a null pointer. ai_addr must be zero or a null pointer. ai_next must be zero or a null pointer.

Other values in the addrinfo structure provided in the hints parameter indicate specific requirements. For example, if the caller handles only TCP and does not handle UDP, the ai_socktype member should be set to SOCK_STREAM. For another example, if the caller handles only IPv4 and does not handle IPv6, the ai_family member should be set to PF_INET. If the hints parameter is a null pointer, the getaddrinfo() function treats it as if the addrinfo structure in hints were initialized with its ai_family member set to PF_UNSPEC and all other members set to zero. Macros in the Winsock header file define the mixed-case function name GetAddrInfo() to getaddrinfo(); either spelling is acceptable.
Program Example

The following example demonstrates the use of the getaddrinfo() function.


// Run on Windows Xp Pro, Visual C++ .Net 1.1 #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> int main() { // Declare variables WSADATA wsaData; // Initialize Winsock, request the Winsock 2.2 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if(iResult != NO_ERROR) printf("Error at WSAStartup().\n"); else printf("WSAStartup() is OK.\n"); // Declare and initialize variables. char* ip = "127.0.0.1"; char* port = "55555"; struct addrinfo aiHints; struct addrinfo *aiList = NULL; int retVal; // Setup the hints address info structure // which is passed to the getaddrinfo() function memset(&aiHints, 0, sizeof(aiHints)); aiHints.ai_family = AF_INET; aiHints.ai_socktype = SOCK_STREAM; aiHints.ai_protocol = IPPROTO_TCP; // // // // if { Call getaddrinfo(). If the call succeeds, the aiList variable will hold a linked list of addrinfo structures containing response information about the host ((retVal = getaddrinfo(ip, port, &aiHints, &aiList)) != 0)

printf("getaddrinfo() failed.\n"); } else printf("getaddrinfo() is OK.\n"); freeaddrinfo(aiList); WSACleanup(); return 0; }

Figure 2

Ensure that the development environment targets the newest version of ws2tcpip.h which includes structure and function definitions for addrinfo() and getaddrinfo(), respectively. Use of ai_flags in the hints parameter Flags in the ai_flags member of the optional addrinfo structure provided in the hints parameter are as follows: AI_PASSIVE AI_CANONNAME AI_NUMERICHOST

Setting the AI_PASSIVE flag indicates the caller intends to use the returned socket address structure in a call to the bind() function. When the AI_PASSIVE flag is set and nodename is a null pointer, the IP address portion of the socket address structure is set to INADDR_ANY for IPv4 addresses and IN6ADDR_ANY_INIT for IPv6 addresses. When the AI_PASSIVE flag is not set, the returned socket address structure is ready for a call to the connect() function for a connection-oriented protocol, or ready for a call to either the connect(), sendto(), or send() functions for a connectionless protocol. If the nodename parameter is a null pointer in this case, the IP address portion of the socket address structure is set to the loopback address. If neither AI_CANONNAME nor AI_NUMERICHOST is used, the getaddrinfo() function attempts resolution. If a literal string is passed getaddrinfo() attempts to convert the string, and if a host name is passed the getaddrinfo() function attempts to resolve it. When the AI_CANONNAME bit is set and the getaddrinfo() function returns success, the ai_canonname member in the hints parameter points to a NULL-terminated string that contains the canonical name of the specified node. The gettaddrinfo() function can return success when the AI_CANNONNAME flag is set, yet the ai_canonname member in the associated addrinfo structure is null. Therefore, the recommended use of the AI_CANONNAME flag includes testing whether the ai_canonname member in the associated addrinfo structure is null. When the AI_NUMERICHOST bit is set, the nodename parameter must contain a non-NULL numeric host address string, otherwise the EAI_NONAME error is returned. This prevents a name resolution service from being called; all information returned by the getaddrinfo() function is dynamically allocated.
Freeing Address Information from Dynamic Allocation

All information returned by the getaddrinfo() function is dynamically allocated, including all addrinfo structures, socket address structures, and canonical host name strings pointed to by addrinfo structures. To return that information to the system, call the freeaddrinfo() function. WINDOWS SOCKET: PROGRAM EXAMPLES PART 10 addrinfo
Item Description

Structure addrinfo. Used by the getaddrinfo() function to hold host address information. Info
typedef struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; Definition size_t ai_addrlen; char* ai_canonname; struct sockaddr* ai_addr; struct addrinfo* ai_next; } addrinfo;

Members ai_flags Flags that indicate options used in the getaddrinfo() function. See AI_PASSIVE, AI_CANONNAME, and AI_NUMERICHOST. ai_family Protocol family, such as PF_INET. ai_socktype Socket type, such as SOCK_RAW, SOCK_STREAM, or SOCK_DGRAM. ai_protocol Protocol, such as IPPROTO_TCP or IPPROTO_UDP. For protocols other than IPv4 and IPv6, set ai_protocol to zero.

ai_addrlen Length of the ai_addr member, in bytes. ai_canonname Canonical name for the host. ai_addr Pointer to a sockaddr structure. ai_next Pointer to the next structure in a linked list. This parameter is set to NULL in the last addrinfo structure of a linked list. Header file Remark <winsock2.h>, <ws2tcpip.h>. Declared in ws2tcpip.h; include wspiapi.h for Windows 95/98/Me, Windows 2000 and Windows NT.
Table 1

freeaddrinfo()
Item Description

Function Use Prototype

freeaddrinfo(). Frees address information that the getaddrinfo() function dynamically allocates in its addrinfo structures.
void freeaddrinfo(struct addrinfo* ai);

ai [in] Pointer to the addrinfo structure or linked list of addrinfo structures to Parameters be freed. All dynamic storage pointed to within the addrinfo structure(s) is also freed. Return value This function has no return values. Include file <winsock2.h>, <ws2tcpip.h> ws2_32.lib Library Declared in ws2tcpip.h; include wspiapi.h for Windows 95/98/Me, Windows 2000 and Windows NT. The freeaddrinfo() function frees the initial addrinfo structure pointed to in its ai parameter, including any buffers to which its members point, then continues freeing any addrinfo Remark structures linked by its ai_next member. The freeaddrinfo() function continues freeing linked structures until a NULL ai_next member is encountered. Macros in the Winsock header file define the mixed-case function name FreeAddrInfo() to freeaddrinfo(); either spelling is acceptable.
Table 2

Program Example

For the program example that demonstrates the use of the send() functions on server and client please refer to the previous program examples. Complete client-server program example The following codes are server and client program examples that used the previous discussed Winsock functions and structures. In this case, to make the client-server communication possible you have to make the server settings (through the arguments- protocol, port number etc.) must match with the client settings. For example if you choose to run the UDP server, the client also must be UDP client. Please run the server program first and you can run the client from different computers. In this example the server and client have been run using the default values of arguments on local Windows Xp Pro machine.
/* Server program example for IPv4 */ #define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #define DEFAULT_PORT 2007

// default TCP socket type #define DEFAULT_PROTO SOCK_STREAM void Usage(char *progname) { fprintf(stderr,"Usage: %s -p [protocol] -e [port_num] -i [ip_address]\n", progname); fprintf(stderr,"Where:\n\t- protocol is one of TCP or UDP\n"); fprintf(stderr,"\t- port_num is the port to listen on\n"); fprintf(stderr,"\t- ip_address is the ip address (in dotted\n"); fprintf(stderr,"\t decimal notation) to bind to. But it is not useful here...\n"); fprintf(stderr,"\t- Hit Ctrl-C to terminate server program...\n"); fprintf(stderr,"\t- The defaults are TCP, 2007 and INADDR_ANY.\n"); WSACleanup(); exit(1); } int main(int argc, char **argv) { char Buffer[128]; char *ip_address= NULL; unsigned short port=DEFAULT_PORT; int retval; int fromlen; int i; int socket_type = DEFAULT_PROTO; struct sockaddr_in local, from; WSADATA wsaData; SOCKET listen_socket, msgsock; /* Parse arguments, if there are arguments supplied */ if (argc > 1) { for(i=1; i<argc; i++) { // switches or options... if ((argv[i][0] == '-') || (argv[i][0] == '/')) { // Change to lower...if any switch(tolower(argv[i][1])) { // if -p or /p case 'p': if (!stricmp(argv[i+1], "TCP")) socket_type = SOCK_STREAM; else if (!stricmp(argv[i+1], "UDP")) socket_type = SOCK_DGRAM; else Usage(argv[0]); i++; break; // if -i or /i, for server it is not so useful... case 'i': ip_address = argv[++i]; break; // if -e or /e case 'e': port = atoi(argv[++i]); break; // No match... default: Usage(argv[0]); break; } } else Usage(argv[0]); } } // Request Winsock version 2.2 if ((retval = WSAStartup(0x202, &wsaData)) != 0) { fprintf(stderr,"Server: WSAStartup() failed with error %d\n", retval); WSACleanup(); return -1; } else printf("Server: WSAStartup() is OK.\n"); if (port == 0) { Usage(argv[0]); }

local.sin_family = AF_INET; local.sin_addr.s_addr = (!ip_address) ? INADDR_ANY:inet_addr(ip_address); /* Port MUST be in Network Byte Order */ local.sin_port = htons(port); // TCP socket listen_socket = socket(AF_INET, socket_type,0); if (listen_socket == INVALID_SOCKET){ fprintf(stderr,"Server: socket() failed with error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else printf("Server: socket() is OK.\n"); // bind() associates a local address and port combination with the // socket just created. This is most useful when the application is a // server that has a well-known port that clients know about in advance. if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR) { fprintf(stderr,"Server: bind() failed with error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else printf("Server: bind() is OK.\n"); // So far, everything we did was applicable to TCP as well as UDP. // However, there are certain steps that do not work when the server is // using UDP. We cannot listen() on a UDP socket. if (socket_type != SOCK_DGRAM) { if (listen(listen_socket,5) == SOCKET_ERROR) { fprintf(stderr,"Server: listen() failed with error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else printf("Server: listen() is OK.\n"); } printf("Server: %s: I'm listening and waiting connection\non port %d, protocol %s\n", argv[0], port, (socket_type == SOCK_STREAM)?"TCP":"UDP"); while(1) { fromlen =sizeof(from); // accept() doesn't make sense on UDP, since we do not listen() if (socket_type != SOCK_DGRAM) { msgsock = accept(listen_socket, (struct sockaddr*)&from, &fromlen); if (msgsock == INVALID_SOCKET) { fprintf(stderr,"Server: accept() error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else printf("Server: accept() is OK.\n"); printf("Server: accepted connection from %s, port %d\n", inet_ntoa(from.sin_addr), htons(from.sin_port)) ; } else

msgsock = listen_socket;

// // // // if else {

In the case of SOCK_STREAM, the server can do recv() and send() on the accepted socket and then close it. However, for SOCK_DGRAM (UDP), the server will do recvfrom() and sendto() in a loop. (socket_type != SOCK_DGRAM) retval = recv(msgsock, Buffer, sizeof(Buffer), 0);

retval = recvfrom(msgsock,Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, &fromlen); printf("Server: Received datagram from %s\n", inet_ntoa(from.sin_addr)); } if (retval == SOCKET_ERROR) { fprintf(stderr,"Server: recv() failed: error %d\n", WSAGetLastError()); closesocket(msgsock);

continue; } else printf("Server: recv() is OK.\n"); if (retval == 0) { printf("Server: Client closed connection.\n"); closesocket(msgsock); continue; } printf("Server: Received %d bytes, data \"%s\" from client\n", retval, Buffer); printf("Server: Echoing the same data back to client...\n"); if (socket_type != SOCK_DGRAM) retval = send(msgsock, Buffer, sizeof(Buffer), 0); else retval = sendto(msgsock, Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, fromlen); if (retval == SOCKET_ERROR) { fprintf(stderr,"Server: send() failed: error %d\n", WSAGetLastError()); } else printf("Server: send() is OK.\n"); if (socket_type != SOCK_DGRAM) { printf("Server: I'm waiting more connection, try running the client\n"); printf("Server: program from the same computer or other computer...\n"); closesocket(msgsock); } else printf("Server: UDP server looping back for more requests\n"); continue; } } return 0;

Figure 1 The following is the client program.


// Client program example #define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #define DEFAULT_PORT 2007 // TCP socket type #define DEFAULT_PROTO SOCK_STREAM void Usage(char *progname) { fprintf(stderr,"Usage: %s -p [protocol] -n [server name/IP] -e [port_num] -l [iterations]\n", progname); fprintf(stderr,"Where:\n\tprotocol is one of TCP or UDP\n"); fprintf(stderr,"\t- server is the IP address or name of server\n");

fprintf(stderr,"\tfprintf(stderr,"\tfprintf(stderr,"\tfprintf(stderr,"\tfprintf(stderr,"\tWSACleanup(); exit(1); }

port_num is the port to listen on\n"); iterations is the number of loops to execute.\n"); (-l by itself makes client run in an infinite loop,\n"); Hit Ctrl-C to terminate it)\n"); The defaults are TCP , localhost and 2007\n");

int main(int argc, char **argv) { char Buffer[128]; // default to localhost char *server_name= "localhost"; unsigned short port = DEFAULT_PORT; int retval, loopflag = 0; int i, loopcount, maxloop=-1; unsigned int addr; int socket_type = DEFAULT_PROTO; struct sockaddr_in server; struct hostent *hp; WSADATA wsaData; SOCKET conn_socket; if (argc >1) { for(i=1; i<argc; i++) { if ((argv[i][0] == '-') || (argv[i][0] == '/')) { switch(tolower(argv[i][1])) { case 'p': if (!stricmp(argv[i+1], "TCP")) socket_type = SOCK_STREAM; else if (!stricmp(argv[i+1], "UDP")) socket_type = SOCK_DGRAM; else Usage(argv[0]); i++; break; case 'n': server_name = argv[++i]; break; case 'e': port = atoi(argv[++i]); break; case 'l': loopflag =1; if (argv[i+1]) { if (argv[i+1][0] != '-') maxloop = atoi(argv[i+1]); } else maxloop = -1; i++; break; default: Usage(argv[0]); break; } } else Usage(argv[0]); } } if ((retval = WSAStartup(0x202, &wsaData)) != 0) { fprintf(stderr,"Client: WSAStartup() failed with error %d\n", retval); WSACleanup(); return -1; } else printf("Client: WSAStartup() is OK.\n"); if (port == 0) { Usage(argv[0]); } // Attempt to detect if we should call gethostbyname() or // gethostbyaddr() if (isalpha(server_name[0])) { // server address is a name

hp = gethostbyname(server_name); } else { // Convert nnn.nnn address to a usable one addr = inet_addr(server_name); hp = gethostbyaddr((char *)&addr, 4, AF_INET); } if (hp == NULL ) { fprintf(stderr,"Client: Cannot resolve address \"%s\": Error %d\n", server_name, WSAGetLastError()); WSACleanup(); exit(1); } else printf("Client: gethostbyaddr() is OK.\n"); // Copy the resolved information into the sockaddr_in structure memset(&server, 0, sizeof(server)); memcpy(&(server.sin_addr), hp->h_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = htons(port); conn_socket = socket(AF_INET, socket_type, 0); /* Open a socket */ if (conn_socket <0 ) { fprintf(stderr,"Client: Error Opening socket: Error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else printf("Client: socket() is OK.\n"); // Notice that nothing in this code is specific to whether we // are using UDP or TCP. // We achieve this by using a simple trick. // When connect() is called on a datagram socket, it does not // actually establish the connection as a stream (TCP) socket // would. Instead, TCP/IP establishes the remote half of the // (LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping. // This enables us to use send() and recv() on datagram sockets, // instead of recvfrom() and sendto() printf("Client: Client connecting to: %s.\n", hp->h_name); if (connect(conn_socket, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) { fprintf(stderr,"Client: connect() failed: %d\n", WSAGetLastError()); WSACleanup(); return -1; } else printf("Client: connect() is OK.\n"); // Test sending some string loopcount = 0; while(1) { wsprintf(Buffer,"This is a test message from client #%d", loopcount++); retval = send(conn_socket, Buffer, sizeof(Buffer), 0); if (retval == SOCKET_ERROR) { fprintf(stderr,"Client: send() failed: error %d.\n", WSAGetLastError()); WSACleanup(); return -1; } else printf("Client: send() is OK.\n"); printf("Client: Sent data \"%s\"\n", Buffer); retval = recv(conn_socket, Buffer, sizeof(Buffer), 0); if (retval == SOCKET_ERROR) fprintf(stderr,"Client: recv() failed: error %d.\n", WSAGetLastError()); closesocket(conn_socket); WSACleanup(); return -1; } else printf("Client: recv() is OK.\n"); // We are not likely to see this with UDP, since there is no // 'connection' established. if (retval == 0) printf("Client: Server closed connection.\n"); closesocket(conn_socket);

WSACleanup(); return -1;

printf("Client: Received %d bytes, data \"%s\" from server.\n", retval, Buffer); if (!loopflag) printf("Client: Terminating connection...\n"); break; } else

} } closesocket(conn_socket); WSACleanup(); return 0; }

if ((loopcount >= maxloop) && (maxloop >0)) break;

The following is an output when the client program has been run twice using the default arguments. Remember that you have to run the server program first.
C:\>myclient Usage: myclient -p [protocol] -n [server name/IP] -e [port_num] -l [iterations] Where: protocol is one of TCP or UDP - server is the IP address or name of server - port_num is the port to listen on - iterations is the number of loops to execute. - (-l by itself makes client run in an infinite loop, - Hit Ctrl-C to terminate it) - The defaults are TCP , localhost and 2007 C:\>myclient -p TCP -n 127.0.0.1 -e 5656 -l 3 Client: WSAStartup() is OK. Client: gethostbyaddr() is OK. Client: socket() is OK. Client: Client connecting to: localhost. Client: connect() is OK. Client: send() is OK. Client: Sent data "This is a test message from client #0" Client: recv() is OK. Client: Received 128 bytes, data "This is a test message from client #0" from server. Client: send() is OK. Client: Sent data "This is a test message from client #1" Client: recv() failed: error 10053. C:\>myclient -p TCP -n 127.0.0.1 -e 5656 -l 3 Client: WSAStartup() is OK. Client: gethostbyaddr() is OK. Client: socket() is OK. Client: Client connecting to: localhost. Client: connect() is OK. Client: send() is OK. Client: Sent data "This is a test message from client #0" Client: recv() is OK. Client: Received 128 bytes, data "This is a test message from client #0" from server. Client: send() is OK. Client: Sent data "This is a test message from client #1" Client: recv() failed: error 10053. C:\>

Notice that the iterations is not working. And the server console output is shown below after the same client program has been run twice.
C:\>mywinsock Usage: mywinsock -p [protocol] -e [port_num] -i [ip_address] Where: - protocol is one of TCP or UDP - port_num is the port to listen on - ip_address is the ip address (in dotted decimal notation) to bind to. But it is not useful here... - Hit Ctrl-C to terminate server program...

- The defaults are TCP, 2007 and INADDR_ANY. C:\>mywinsock -p TCP -e 5656 Server: WSAStartup() is OK. Server: socket() is OK. Server: bind() is OK. Server: listen() is OK. Server: mywinsock: I'm listening and waiting connection on port 5656, protocol TCP Server: accept() is OK. Server: accepted connection from 127.0.0.1, port 1031 Server: recv() is OK. Server: Received 128 bytes, data "This is a test message from client #0" from client Server: Echoing the same data back to client... Server: send() is OK. Server: I'm waiting more connection, try running the client Server: program from the same computer or other computer... Server: accept() is OK. Server: accepted connection from 127.0.0.1, port 1032 Server: recv() is OK. Server: Received 128 bytes, data "This is a test message from client #0" from client Server: Echoing the same data back to client... Server: send() is OK. Server: I'm waiting more connection, try running the client Server: program from the same computer or other computer... _

The following console outputs are the previous client-server program examples re-compiled using Visual C++ 6.0 and using public IPs.

Figure 2

Figure 3

Figure 4

Potrebbero piacerti anche