< Winsock 2 C Programming Index | IP Address & Winsock2 APIs >


 

 

An Intro to Windows Socket Programming with C

Part 1

 

 

What do we have in this chapter 1 part 1?

  1. Winsock Headers and Libraries

  2. Initializing Winsock

  3. Error Checking and Handling

 

Winsock is a standard application programming interface (API) that allows two or more applications (or processes) to communicate either on the same machine or across a network and is primarily designed to foster data communication over a network. It is important to understand that Winsock is a network programming interface and not a protocol. Winsock provides the programming interface for applications to communicate using popular network protocols such as Transmission Control Protocol/Internet Protocol (TCP/IP) and Internetwork Packet Exchange (IPX). The Winsock interface inherits a great deal from the BSD Sockets implementation on UNIX platforms. In Windows environments, the interface has evolved into a truly protocol-independent interface, especially with the release of Winsock 2.

The examples presented in this chapter help to provide an understanding of the Winsock calls that are required for accepting connections, establishing connections, and sending and receiving data. Because the purpose of this chapter is to learn these fundamental Winsock calls, the examples presented use straight blocking Winsock calls.

You can differentiate the two functions with the WSA prefix. If Winsock 2 updated or added a new API function in its specification, the function name is prefixed with WSA. For example, the Winsock 1 function to create a socket is simply socket(). Winsock 2 introduces a newer version named WSASocket() that is capable of using some of the new features made available in Winsock 2. There are a few exceptions to this naming rule. WSAStartup(), WSACleanup(), WSARecvEx(), and WSAGetLastError() are in the Winsock 1.1 specification. If you fail to find the related Winsock headers in your machine or programming environment, you may want to read Visual .NET doc 1 and Visual .NET doc 2 articles first. Those articles also show how to add the Winsock link library, ws2_32.lib to the Visual C++ project.

 

Winsock Headers and Libraries

 

When developing new applications you should target the Winsock 2 specification by including WINSOCK2.H in your application. For compatibility with older Winsock applications and when developing on Windows CE platforms, WINSOCK.H is available. There is also an additional header file: MSWSOCK.H, which targets Microsoft-specific programming extensions that are normally used for developing high performance Winsock applications.

When compiling your application with WINSOCK2.H, you should link with WS2_32.LIB library. When using WINSOCK.H (as on Windows CE) you should use WSOCK32.LIB. If you use extension APIs from MSWSOCK.H, you must also link with MSWSOCK.LIB (get the idea here  - VC++ .NET or here - VC++ 6). Once you have included the necessary header files and link environment, you are ready to begin coding your application, which requires initializing Winsock.

 

Initializing Winsock

 

Every Winsock application must load the appropriate version of the Winsock DLL. If you fail to load the Winsock library before calling a Winsock function, the function returns a SOCKET_ERROR; the error will be WSANOTINITIALISED. Loading the Winsock library is accomplished by calling the WSAStartup() function, which is defined as:

 

int WSAStartup(

    WORD wVersionRequested,

    LPWSADATA lpWSAData

);

 

The wVersionRequested parameter is used to specify the version of the Winsock library you want to load. The high-order byte specifies the minor version of the requested Winsock library, while the low-order byte is the major version. You can use the handy macro MAKEWORD(x, y), in which x is the high byte and y is the low byte, to obtain the correct value for wVersionRequested. The lpWSAData parameter is a pointer to a LPWSADATA structure that WSAStartup() fills with information related to the version of the library it loads:

 

typedef struct WSAData

{

    WORD           wVersion;

    WORD           wHighVersion;

    char           szDescription[WSADESCRIPTION_LEN + 1];

    char           szSystemStatus[WSASYS_STATUS_LEN + 1];

    unsigned short iMaxSockets;

    unsigned short iMaxUdpDg;

    char FAR *     lpVendorInfo;

} WSADATA, * LPWSADATA;

 

WSAStartup() sets the first field, wVersion, to the Winsock version you will be using. The wHighVersion parameter holds the highest version of the Winsock library available. Remember that in both of these fields, the high-order byte represents the Winsock minor version, and the low-order byte is the major version. The szDescription and szSystemStatus fields are set by the particular implementation of Winsock and aren't really useful. Do not use the next two fields, iMaxSockets and iMaxUdpDg. They are supposed to be the maximum number of concurrently open sockets and the maximum datagram size; however, to find the maximum datagram size you should query the protocol information through WSAEnumProtocols().

The maximum number of concurrent sockets isn't some magic number, it depends more on the physical resources available. Finally, the lpVendorInfo field is reserved for vendor-specific information regarding the implementation of Winsock. This field is not used on any Windows platforms.

For the most part, when writing new applications you will load the latest version of the Winsock library currently available. Remember that if, for example, Winsock 3 is released, your application that loads version 2.2 should run as expected. If you request a Winsock version later than that which the platform supports, WSAStartup() will fail. Upon return, the wHighVersion of the WSADATA structure will be the latest version supported by the library on the current system. When your application is completely finished using the Winsock interface, you should call WSACleanup(), which allows Winsock to free up any resources allocated by Winsock and cancel any pending Winsock calls that your application made. WSACleanup() is defined as:

 

int WSACleanup(void);

 

Failure to call WSACleanup when your application exits is not harmful because the operating system will free up resources automatically; however, your application will not be following the Winsock specification. Also, you should call WSACleanup for each call that is made to WSAStartup.

 

Error Checking and Handling

 

We'll first cover error checking and handling, as they are vital to writing a successful Winsock application. It is actually common for Winsock functions to return an error; however, there are some cases in which the error is not critical and communication can still take place on that socket. The most common return value for an unsuccessful Winsock call is SOCKET_ERROR, although this is certainly not always the case. When covering each API call in detail, we'll point out the return value corresponding to an error. The constant SOCKET_ERROR actually is -1. If you make a call to a Winsock function and an error condition occurs, you can use the function WSAGetLastError() to obtain a code that indicates specifically what happened. This function is defined as:

 

int WSAGetLastError (void);

 

A call to the function after an error occurs will return an integer code for the particular error that occurred. These error codes returned from WSAGetLastError() all have predefined constant values that are declared in either WINSOCK.H or WINSOCK2.H, depending on the version of Winsock. The only difference between the two header files is that WINSOCK2.H contains more error codes for some of the newer API functions and capabilities introduced in Winsock 2. The constants defined for the various error codes (with #define directives) generally begin with WSAE. On the flip side of WSAGetLastError(), there is WSASetLastError(), which allows you to manually set error codes that WSAGetLastError() retrieves.

The following program demonstrates how to construct a skeleton Winsock application based on the discussion so far:

 

#include <winsock2.h>

 

void main(void)

{

   WSADATA wsaData;

 

   // Initialize Winsock version 2.2

   if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)

   {

      printf("WSAStartup failed with error %ld\n", WSAGetLastError());

      return;

   }

 

   // Setup Winsock communication code here

 

   // When your application is finished call WSACleanup

   if (WSACleanup() == SOCKET_ERROR)

   {

      printf("WSACleanup failed with error %d\n", WSAGetLastError());

   }

}

 

Let try this program using Visual C++ 2008 Express Edition. First and foremost let change the newly installed VC++ startup page to last loaded solution. You can skip this ‘optional’ step. Click Tools menu > Options sub menu.

 

Windows socket and C programming: Invoking the Visual C++ Options page

 

Expand Environment folder > Select Startup link > Set the At Startup: to Load last loaded solution > Click OK.

 

Windows socket and C programming: changing the startup page of the Visual C++ IDE

 

1.      Then we can start creating the Win32 console application project. Click File menu > Project sub menu to create a new project.

 

Windows socket and C programming: creating a new project for Visual C++

 

2.      Select Win32 for the Project types: and Win32 Console Application for the Templates:. Put the project and solution name. Adjust the project location if needed and click OK.

 

Windows socket and C programming: selecting the Win32 console application

 

3.      Click Next for the Win32 Application Wizard Overview page. We will remove all the unnecessary project items.

 

Windows socket and C programming: new project wizard overview page

 

4.      In the Application page, select Empty project for the Additional options:. Leave others as given and click Finish.

 

Windows socket and C programming: the Win32 console application project settings

 

5.      Next, we need to add new source file. Click Project menu > Add New Item sub menu or select the project folder in the Solution Explorer > Select Add menu > Select New Item sub menu.

 

Windows socket and C programming: adding new item, source code file to the existing Visual C++ project

 

Windows socket and C programming: invoking the Add New Item from the Visual C++ Solution explorer

 

6.      Select C++ File (.cpp) for the Templates:. Put the source file name and click Add. Although the extension is .cpp, Visual C++ IDE will recognize that the source code used is C based on the Compile as C Code (/TC) option which will be set in the project property page later.

 

Windows socket and C programming: selecting the C++ File templates

 

7.      Now, add the source code as given below.

 

#include <winsock2.h>

#include <stdio.h>

 

int main(void)

{

   WSADATA wsaData;

   int RetCode;

 

   // Initialize Winsock version 2.2

   if ((RetCode = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)

   {

      printf("WSAStartup failed with error %d\n", RetCode);

      return 1;

   }

   else

   {

        printf("The Winsock dll found!\n");

        printf("The current status is: %s.\n", wsaData.szSystemStatus);

   }

 

   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));

        // When your application is finished call WSACleanup

        WSACleanup();

        // and exit

        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));

 

        // Setup Winsock communication code here

 

        // When your application is finished call WSACleanup

        if (WSACleanup() == SOCKET_ERROR)

             printf("WSACleanup failed with error %d\n", WSAGetLastError());

        // and exit

        return 1;

   }

}

 

8.      Before we can build this Winsock C Win32 console application project, we need to set the project to be compiled as C code and link to ws2_32.lib, the Winsock2 library. Invoke the project property page.

 

------------------------------------------------------------

Windows socket and C programming: invoking the Visual C++ project property page

 

9.      Expand the Configuration folder > Expand the C/C++ sub folder. Select the Advanced link and for the Compile As option, select Compile as C Code (/TC).

 

Windows socket and C programming: setting the Visual C++ project to be compiled as C code

 

10. Next, expand the Linker folder and select the Input link. For the Additional Dependencies option, click the ellipses at the end of the empty field on the right side.

 

Windows socket and C programming: adding the additional dependencies, in this case a library in the Visual C++ project

 

11. Manually, type the library name and click OK.

 

Windows socket and C programming: typing the ws2_32.lib, a winsock2 library manually

 

12. Or you can just directly type the library name in the empty field on the right of the Additional Dependencies. Click OK.

 

Windows socket and C programming: the added additional dependencies which is a Winsock2 library

 

13. Build the project and make sure there is no error which can be seen (if any) in the Output window normally docked at the bottom of the IDE by default.

 

Windows socket and C programming: building the Visual C++ project

 

14. Run the project.

 

Windows socket and C programming: running the Visual C++ project

 

15. If there is no error, a sample of expected output is shown below.

 

Windows socket and C programming: a sample Winsock2 console output

 

Well, after completing this exercise you should be familiar with the steps to create an empty Win32 console application project. Those steps will be repeated for almost all the Winsock2 projects in this tutorial. Now we are ready to describe how to set up communication using a network protocol.

 

 

 


< Winsock 2 C Programming Index | IP Address & Winsock2 APIs >