An Intro to Windows Socket (Winsock2) Programming 13

 

 

 

TCP Receiver/Server With select() Example

 

1.   While in the Visual C++ IDE, click File menu > Project sub menu to create a new project.

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.

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

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

 

 

Windows Socket (Winsock2) Programming and  C Language: creating new TCP server/receiver Win32 console application

 

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.

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 (Winsock2) Programming and  C Language: adding the C++ source code to the existing empty Win32 console application

 

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

 

#include<winsock2.h>

#include<stdio.h>

 

// #pragma comment(lib, ws2_32.lib)

 

// A sample of the select() return value

int recvTimeOutTCP(SOCKET socket, long sec, long usec)

{

    // Setup timeval variable

    struct timeval timeout;

    struct fd_set fds;

 

            // assign the second and microsecond variables

    timeout.tv_sec = sec;

    timeout.tv_usec = usec;

    // Setup fd_set structure

    FD_ZERO(&fds);

    FD_SET(socket, &fds);

    // Possible return values:

    // -1: error occurred

    // 0: timed out

    // > 0: data ready to be read

    return select(0, &fds, 0, 0, &timeout);

}

 

int main(int argc, char **argv)

{

            WSADATA               wsaData;

            SOCKET                   ListeningSocket, NewConnection;

            SOCKADDR_IN      ServerAddr, SenderInfo;

            int                               Port = 7171;

            // Receiving part

            char                            recvbuff[1024];

            int                                ByteReceived, i, nlen, SelectTiming;

           

            // Initialize Winsock version 2.2

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

            {

                        // The WSAGetLastError() function is one of the only functions

                        // in the Winsock 2.2 DLL that can be called in the case of a WSAStartup failure

                        printf(Server: WSAStartup failed with error %ld.\n, WSAGetLastError());

                        // Exit with error

                        return 1;

            }

            else

            {

                        printf(Server: The Winsock DLL found!\n);

                        printf(Server: 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(Server: The dll do not support the Winsock version %u.%u!\n, LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));

                        // Do the clean up

                        WSACleanup();

                        // and exit with error

                        return 1;

            }

            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 is %u.%u\n, LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));

            }

           

            // Create a new socket to listen for client connections.

            ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

           

            // Check for errors to ensure that the socket is a valid socket.

            if (ListeningSocket == INVALID_SOCKET)

            {

                        printf(Server: Error at socket(), error code: %ld.\n, WSAGetLastError());

                        // Clean up

                        WSACleanup();

                        // and exit with error

                        return 1;

            }

            else

                        printf(Server: socket() is OK!\n);

           

            // Set up a SOCKADDR_IN structure that will tell bind that we

            // want to listen for connections on all interfaces using port 7171.

 

            // The IPv4 family

            ServerAddr.sin_family = AF_INET;

            // host-to-network byte order

            ServerAddr.sin_port = htons(Port);

            // Listen on all interface, host-to-network byte order

            ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

           

            // Associate the address information with the socket using bind.

            // Call the bind function, passing the created socket and the sockaddr_in

            // structure as parameters. Check for general errors.

            if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)

            {

                        printf(Server: bind() failed! Error code: %ld.\n, WSAGetLastError());

                        // Close the socket

                        closesocket(ListeningSocket);

                        // Do the clean up

                        WSACleanup();

                        // and exit with error

                        return 1;

            }

            else

                        printf(Server: bind() is OK!\n);

 

            // Listen for client connections with a backlog of 5

            if (listen(ListeningSocket, 5) == SOCKET_ERROR)

            {

                        printf(Server: listen(): Error listening on socket %ld.\n, WSAGetLastError());

                        // Close the socket

                        closesocket(ListeningSocket);

                        // Do the clean up

                        WSACleanup();

                        // Exit with error

                        return 1;

            }

            else

                        printf(Server: listen() is OK, I'm listening for connections...\n);

           

            // Set 10 seconds 10 useconds timeout

            SelectTiming = recvTimeOutTCP(ListeningSocket, 10, 10);

           

            switch (SelectTiming)

            {

                        case 0:

                                    // Timed out, do whatever you want to handle this situation

                                    printf(\nServer: Timeout lor while waiting you retard client!...\n);

                                    break;

                        case -1:

                                    // Error occurred, more tweaking here and the recvTimeOutTCP()...

                                    printf(\nServer: Some error encountered with code number: %ld\n, WSAGetLastError());

                                    break;

                        default:

                                    {

                                                // Accept a new connection when available. 'while' always true

                                                while(1)

                                                {

                                                            // Reset the NewConnection socket to SOCKET_ERROR

                                                            // Take note that the NewConnection socket in not listening

                                                            NewConnection = SOCKET_ERROR;

                                                            // While the NewConnection socket equal to SOCKET_ERROR

                                                            // which is always true in this case...

                                                            while(NewConnection == SOCKET_ERROR)

                                                            {

                                                                        // Accept connection on the ListeningSocket socket and assign

                                                                        // it to the NewConnection socket, let the ListeningSocket

                                                                        // do the listening for more connection

                                                                        NewConnection = accept(ListeningSocket, NULL, NULL);

                                                                        printf(\nServer: accept() is OK...\n);

                                                                        printf(Server: New client got connected, ready to receive and send data...\n);

                                                                       

                                                                        // At this point you can do two things with these sockets

                                                                        // 1. Wait for more connections by calling accept again on ListeningSocket (loop)

                                                                        // 2. Start sending or receiving data on NewConnection.

                                                                        ByteReceived = recv(NewConnection, recvbuff, sizeof(recvbuff), 0);

                                                                       

                                                                        // When there is data

                                                                        if ( ByteReceived > 0 )

                                                                        {

                                                                                    printf(Server: recv() looks fine....\n);

 

                                                                                    // Some info on the receiver side...

                                                                                    getsockname(ListeningSocket, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr));

                                                                                    printf(Server: Receiving IP(s) used: %s\n, inet_ntoa(ServerAddr.sin_addr));

                                                                                    printf(Server: Receiving port used: %d\n, htons(ServerAddr.sin_port));

 

                                                                                    // Some info on the sender side

                                                                                    // Allocate the required resources

                                                                                    memset(&SenderInfo, 0, sizeof(SenderInfo));

                                                                                    nlen = sizeof(SenderInfo);

                                                                                   

                                                                                    getpeername(NewConnection, (SOCKADDR *)&SenderInfo, &nlen);

                                                                                    printf(Server: Sending IP used: %s\n, inet_ntoa(SenderInfo.sin_addr));

                                                                                    printf(Server: Sending port used: %d\n, htons(SenderInfo.sin_port));

                                                                                   

                                                                                    // Print the received bytes. Take note that this is the total

                                                                                    // byte received, it is not the size of the declared buffer

                                                                                    printf(Server: Bytes received: %d\n, ByteReceived);

                                                                                    // Print what those bytes represent

                                                                                    printf(Server: Those bytes are: \);

                                                                                    // Print the string only, discard other

                                                                                    // remaining 'rubbish' in the 1024 buffer size

                                                                                    for(i=0;i < ByteReceived;i++)

                                                                                                printf(%c, recvbuff[i]);

                                                                                    printf(\);

                                                                        }

                                                                        // No data

                                                                        else if ( ByteReceived == 0 )

                                                                                    printf(Server: Connection closed!\n);

                                                                        // Others

                                                                        else

                                                                                    printf(Server: recv() failed with error code: %d\n, WSAGetLastError());

                                                            }

                                                           

                                                            // Clean up all the send/recv communication, get ready for new one

                                                            if( shutdown(NewConnection, SD_SEND) != 0)

                                                                        printf(\nServer: Well, there is something wrong with the shutdown(). The error code: %ld\n, WSAGetLastError());

                                                            else

                                                                        printf(\nServer: shutdown() looks OK...\n);

                                                           

                                                            // Well, if there is no more connection in 15 seconds,

                                                            // just exit this listening loop...

                                                            if( recvTimeOutTCP(ListeningSocket, 15, 0) == 0)

                                                                        break;

                                                }

                                    }

            }

 

            printf(\nServer: The listening socket is timeout...\n);

            // When all the data communication and listening finished, close the socket

            if(closesocket(ListeningSocket) != 0)

                        printf(Server: Cannot close \ListeningSocket\ socket. Error code: %ld\n, WSAGetLastError());

            else

                        printf(Server: Closing \ListeningSocket\ socket...\n);

 

            // Finally and optionally, clean up all those WSA setup

            if(WSACleanup() != 0)

                        printf(Server: WSACleanup() failed! Error code: %ld\n, WSAGetLastError());

            else

                        printf(Server: WSACleanup() is OK...\n);

 

            return 0;

}

 

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.

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

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.

11. Manually, type the library name, ws2_32.lib and click OK Or you can just directly type the library name in the empty field on the right of the Additional Dependencies. Click OK. Or add the #pragma comment() directive as shown below in the source code.

 

#pragma comment(lib, ws2_32.lib)

 

12. Build and run the project. If there is no error during the build and run processes, the following shows a sample output that should be expected. Without any connection in 10 seconds and 10 microseconds, the program terminates. We will test this receiver/server program with the sender/client which will be created in the next exercise.

 

Windows Socket (Winsock2) Programming and  C Language: the TCP server with select() in action

 

 

In the meantime, you may want to run the netstat tool, when you run the server program to view the TCP status. In this case we run the following netstat tool which displays all the traffic info for every 5 seconds. You may also redirect the output to a text file using: netstat –a 5 > text_file_name.txt.

 

Windows Socket (Winsock2) Programming and  C Language: the netstat Windows traffic analyzer in action

 

Then we run the server program. The status should be in the listening mode on the specified port. You can have more info on the TCP/IP states diagram at Debugging the TCP.

 

Windows Socket (Winsock2) Programming and  C Language: The TCP select server in the listening mode seen from the netstat screen

 

 

 

< Winsock2 12 | Windows Socket 2 (Winssock2) | Win32 Programming | Winsock2 14 >