Warning: INSERT command denied to user 'dbo292345962'@'74.208.16.27' for table 'watchdog' query: INSERT INTO watchdog (uid, type, message, variables, severity, link, location, referer, hostname, timestamp) VALUES (0, 'php', '%message in %file on line %line.', 'a:4:{s:6:\"%error\";s:12:\"user warning\";s:8:\"%message\";s:399:\"INSERT command denied to user 'dbo292345962'@'74.208.16.27' for table 'captcha_sessions'\nquery: INSERT into captcha_sessions (uid, sid, ip_address, timestamp, form_id, solution, status, attempts) VALUES (0, '5caf57b8f4b9cc186ecd998c50b561a5', '54.87.136.181', 1418970406, 'comment_form', '90ead1e7fe2fe58aa4da6bbbaf31e393', 0, 0)\";s:5:\"%file\";s:62:\"/homepages/25/d199835659/htdocs/ID/modules/captcha/captcha.inc\";s:5:\"%line\";i:99;}� in /homepages/25/d199835659/htdocs/ID/includes/database.mysql.inc on line 135
Winsock Server Tutorial | Inferno Development

Winsock Server Tutorial

This Winsock tutorial will cover C++ Win32 API's winsock commands and basic functions. Reading this tutorial will familiarize you with creating sockets and servers with Winsock2. We will be learning about WSAStartup, socket, bind, listen, and accept functions and in addition the clean-up functions like closesocket and WSACleanup.

Let's begin by including our most important headers. Windows.h is for the Win32 API in C++. Winsock2.h is our winsock library. STDio and STDlib are for small console/standard functions used in C. The STD library headers are not required but then you must delete the dependent functions (like strcpy), and find replacements for them in the Win32 API, which is possible; however, for simplicity I used STD library.

Important Note: If you're using Dev-Cpp or mingw, you must include "libws2_32.a" in your Linker Parameters under Project Options. Just click Add Library in the Parameters tab and find it in your lib folder.
If you're using any other compiler, you should try and find "ws2_32.lib" and make sure it is included in your project linker.

Here are the headers:

#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

Now we just start our main function, you probably will not see a console or any window come up, and that is perfectly fine, but expect to get a lot of Message Boxes:

int main(int argc, char *argv[]){
        WSADATA t_wsa; // WSADATA structure
        WORD wVers; // version number
        int iError; // error number

        wVers = MAKEWORD(2, 2); // Set the version number to 2.2
        iError = WSAStartup(wVers, &t_wsa); // Start the WSADATA

WSADATA is a structure that winsock uses to communicate its startup information, and we named it t_wsa. We also made a WORD wVers which we will use to store our Winsock version number.

We use WSAStartup() to start our Winsock with version 2.2 and we send our empty structure so that WSAStartup will fill it up with useful information.

Now we check for errors that might have occured with WSAStartup:

if(iError != NO_ERROR || iError == 1){
                MessageBox(NULL, (LPCTSTR)"Error at WSAStartup()", (LPCTSTR)"Server::Error", MB_OK|MB_ICONERROR);
                WSACleanup();
                return 0;
        }

If there are errors we should use WSACleanup to make sure we clean all the sockets and exit the program in a clean manner without leaks.

Now we check the version and see if its definitely 2.2! If not, we display a message box error indicated by MessageBox.

        if(LOBYTE(t_wsa.wVersion) != 2 || HIBYTE(t_wsa.wVersion) != 2){
    MessageBox(NULL, (LPCTSTR)"Error at WSAStartup()", (LPCTSTR)"Server::Error", MB_OK|MB_ICONERROR);
                WSACleanup();
                return 0;
        }

Here we create a SOCKET called sServer, which will be used to establish our Socket. We call socket() to create the socket on our variable and then we check if we made any errors while establishing the socket. IPPROTO_TCP means a TCP connection which is different from a UDP connection. AF_INET and SOCK_STREAM are standard ways to create a streaming socket.

        SOCKET sServer;
        sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(sServer == INVALID_SOCKET || iError == 1){
                MessageBox(NULL, (LPCTSTR)"Invalid Socket!", (LPCTSTR)"Server::Error", MB_OK|MB_ICONERROR);
                WSACleanup();
                return 0;
        }

If we have any problems we display "Invalid Socket!" error.

Now we establish a SOCKADDR_IN which basically defines some information for our binding such as IP, port, host, and family. We memset the sinServer variable to its own size. Then we set the family, and INADDR_ANY for the IP which basically means the IP of the current computer. We also use htons to convert 1000 to a network port number for our socket. So this all means that we are going to accept connecting clients through port 1000, so make sure that port is not blocked by your firewall/router:

        SOCKADDR_IN sinServer;
        memset(&sinServer, 0, sizeof(sinServer));

        sinServer.sin_family = AF_INET;
        sinServer.sin_addr.s_addr = INADDR_ANY; // Where to start server?
        sinServer.sin_port = htons(1000); // Port

Now we bind our server information to our socket and check if there is any errors in binding to that port.

        if(bind(sServer, (LPSOCKADDR)&sinServer, sizeof(sinServer)) == SOCKET_ERROR){
                /* failed at starting server */
                MessageBox(NULL, (LPCTSTR)"Could not bind the server!", (LPCTSTR)"Server::Error", MB_OK|MB_ICONERROR);
                WSACleanup();
                return 0;
        }

We now listen for connections at our socket. This allows us to accept "20" max clients to connect at the same time:

        while(listen(sServer, 20) == SOCKET_ERROR){
    Sleep(10);
  }

Let's display a message so we know that our server software is working and is ready for clients.

  MessageBox(NULL, (LPCTSTR)"Waiting for a Client!", (LPCTSTR)"Server::Success", MB_OK);

Now let's establish a Client socket so that we can pick and choose WHICH clients to talk to:

        SOCKET sClient;
        int szlength;

        szlength = sizeof(sinServer);
        sClient = accept(sServer, (LPSOCKADDR)&sinServer, &szlength);

We also accept a client as sClient on the sServer socket. So now we can use sClient to talk to that specific client.

Let's check if our accept succeeded and display the appropriate message. Also be sure to close the server socket if we fail and close the program using return 0:

        if (sClient == INVALID_SOCKET){
                MessageBox(NULL, (LPCTSTR)"Could not accept this client!", (LPCTSTR)"Server::Error", MB_OK|MB_ICONERROR);
    closesocket(sServer);
                WSACleanup();
                return 0;
        } else {
    MessageBox(NULL, (LPCTSTR)"Accepted a Client!", (LPCTSTR)"Server::Success", MB_OK);
  }

Let's send a welcome message to the connecting client. We create a buffer and fill it with our welcome message. Then we use send to send the message to sClient and also make sure we send the length of buffer as well. Keep the last parameter 0 but you can look in the MSDN for more flags and options on last parameter:

        // Now we can send/recv data!
        int iRet;
        char buffer[200];
        strcpy(buffer, "Welcome to our Server!\0");
        iRet = send(sClient, buffer, strlen(buffer), 0);
        if(iRet == SOCKET_ERROR){
                MessageBox(NULL, (LPCTSTR)"Could not send data!", (LPCTSTR)"Server::Error", MB_OK|MB_ICONERROR);
                closesocket(sClient);
    closesocket(sServer);
                WSACleanup();
                return 0;
        }

Let's also create an autoresponse whenever we receive a message letting the client know we got the message. We do some checks to avoid any buffer overflow problems if people write too long messages. We also use HEAP style char for cClientMessage which we will use in our receiving loop.

        char autoresponse[80];
        int bytes;
        strcpy(autoresponse, "Message Received!");
        autoresponse[strlen(autoresponse)-1] = 0;
        MessageBox(NULL, (LPCTSTR)"Server is ready for messages and is hiding!", (LPCTSTR)"Server::Success", MB_OK);
        char *cClientMessage;
        cClientMessage = new char[600];
        cClientMessage[599] = 0;

Make sure the last character is null terminated to eliminate crashes by buffer overflow.

Now we begin our large loop to receive messages using recv and fill the message to our buffer called cClientMessage. If bytes is less than 1 we wait a little and restart the loop. Otherwise we display a message received messagebox to our server administrator and send an autoresponse to the client that sent a message to us. We also check for any errors. At the end we delete our buffer and recreate it since we already received the message. Also we use Sleep(100) to avoid too much CPU consumption which isn't really necessary but helps:

        while(bytes = recv(sClient, cClientMessage, 599, 0)){
    if(bytes < 1){
      Sleep(300);
      continue;
    }
                MessageBox(NULL, (LPCTSTR)cClientMessage, (LPCTSTR)"Server::Message Received", MB_OK|MB_ICONEXCLAMATION);
                iRet = send(sClient, autoresponse, strlen(autoresponse), 0);
                if(iRet == SOCKET_ERROR){
                        MessageBox(NULL, (LPCTSTR)"Could not send response!", (LPCTSTR)"Server::Error", MB_OK|MB_ICONERROR);
                        closesocket(sClient);
            closesocket(sServer);
                        WSACleanup();
                        return 0;
                }
                delete [] cClientMessage;
                cClientMessage = new char[600];
          cClientMessage[599] = 0;
                Sleep(100); // Don't consume too much CPU power.
        }

At the end of our server when our loop stops receiving messages--which is usually when someone Ctrl+Alt+Deletes and ends our Server process since we dont have an EXIT button--we exit with clean up methods and close our sockets and make sure there are no memory leaks. If you want to shut down the server please use Ctrl+Alt+Delete as I wouldn't want to make this tutorial too complex and show you how to exit the server using ESC button or a graphical button.

        delete [] cClientMessage;
        // Cleanup
        closesocket(sClient);
        closesocket(sServer);
        // Shutdown Winsock
        WSACleanup();
        return 0;
}

I hope you enjoyed this detailed tutorial on how to create a Server program and use Winsock for all your internet and socket needs. I hope this also helps explain how many programs communicate with each other online using the TCP connection protocol.

Please look in the same C++ Win32 API category for more tutorials on winsock such as how to create a Client using this same method. You can then create 2 programs one which is the server and one which is the client which you can use to communicate with each other.

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.