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, 'a75fbf9f52f386910a01659fd6b61f8a', '54.196.159.11', 1414164179, 'comment_form', '350c71acd167ab2b319a5ef55ffcc040', 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 Client Tutorial | Inferno Development

Winsock Client Tutorial

This is a continuation of the Winsock Server Tutorial, you can use this to connect to the server created in that server tutorial or make your own server for this.

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, connect, send, and recv functions and in addition the cleaning 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.

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.

First, lets add our headers to be able to use our code:

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

We create our WSADATA structure which we will use to gather information from the Winsock library in this computer. wVers will be used for our version number that we want. iError will be used to check for any errors and display a message box if there is any trouble.

int main(){
        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

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

Lets check the correct version!

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

Now let's create our sClient SOCKET. Using socket() function we establish a TCP socket with the standard settings. Refer to the MSDN library for more options. We check for any errors and we continue.

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

We establish a SOCKADDR_IN which is a structure used to set the settings of this socket. We first memset the sinClient to its own size. Then we use our own IP (if the server is located on another IP just change the strcpy function, 127.0.0.1 means yourself). Of course you should make sure the server runs at this IP on your computer before you try and test the program:

        SOCKADDR_IN sinClient;
        memset(&sinClient, 0, sizeof(sinClient));
 
  char cIP[50];
  strcpy(cIP, "127.0.0.1");
        sinClient.sin_family = AF_INET;
        sinClient.sin_addr.s_addr = inet_addr(cIP); // Where to start server?
        sinClient.sin_port = htons(1000); // Port

Be sure to also add the sin_family, sin_addr being the IP we just set, and the htons(1000) which means we want to set the socket to port 1000.

We connect our socket using our new information to that port and IP. We check for errors and if everything is fine, we set a success message such as "You are connected!":

        if(connect(sClient, (LPSOCKADDR)&sinClient, sizeof(sinClient)) == SOCKET_ERROR){
                /* failed at starting server */
                MessageBox(NULL, (LPCTSTR)"Could not connect to the server!", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
                WSACleanup();
                return 0;
        }
        // Now we can send/recv data!
        int iRet;
        char cBuffer[600];
        MessageBox(NULL, (LPCTSTR)"You are connected! Sending a message to the server (less than 599 characters)!", (LPCTSTR)"Client::Server", MB_OK|MB_ICONEXCLAMATION);

Now lets create a buffer string and add a message we can send to our server once connected. We use send() function to send that message to our socket!

        char buffer[200];
        strcpy(buffer, "Hey server, I just connected!\0");
        iRet = send(sClient, buffer, strlen(buffer), 0);
        if(iRet == SOCKET_ERROR){
                MessageBox(NULL, (LPCTSTR)"Could not send data!", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
                WSACleanup();
                return 0;
        }

Now we create our cServerMessage buffer which will contain server responses whenever we receive any information! Using our while loop we continuously use "recv()" to get any messages the server might be sending us. If bytes becomes SOCKET_ERROR in our loop, it means we had an error and should display the appropriate error message. We use WSACleanup() to make sure we don't have leaks or crashes. If the bytes received is 0 or WSAECONNRESET we know that we have disconnected and therefore we should display an error and shut down the program. If everything goes well we display the message that we receive from the server and we use Sleep to make sure our program doesn't waste too much CPU resources:

        int bytes;
        bytes = SOCKET_ERROR;
        char *cServerMessage;
        cServerMessage = new char[600];
  while(bytes = recv(sClient, cServerMessage, 599, 0)){
    if(bytes == SOCKET_ERROR){
            char cError[500];
                        sprintf(cError, "Connection failed, WINSOCK error code: %d", WSAGetLastError());
                        MessageBox(NULL, (LPCTSTR)cError, (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
                        closesocket(sClient);
        // Shutdown Winsock
        WSACleanup();
      return 0;
    }
    if (bytes == 0 || bytes == WSAECONNRESET) {
      MessageBox(NULL, (LPCTSTR)"Connection Disconnected!", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
      closesocket(sClient);
      // Shutdown Winsock
      WSACleanup();
      return 0;
    }
    if(bytes < 1){
      Sleep(300);
      continue;
    }
    MessageBox(NULL, (LPCTSTR)cServerMessage, (LPCTSTR)"Client::Server Response", MB_OK);
    delete [] cServerMessage;
    cServerMessage = new char[600];
                Sleep(100); // Don't consume too much CPU power.
        }

This section is the end of our program and our clean up in case our messages are finished or we are broken out of the receiving loop. Of course there is no proper way to exit this program except via Ctrl+Alt+Delete and ending the process. The reason being we don't want to over complicate this code for a simple exit method. However, it is standard to code the ESC button to exit or create a GUI for this program using the Win32 C++ API.

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

We close our socket, delete our cServerMessage from the heap and cleanup our winsock data!

Use this sort of code to make different light-weight internet-based programs.

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.