Click here to Skip to main content
15,889,034 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Recently I was making multi-threaded server application which is capable of connecting to multiple clients. But, when I ran the client application, some run-time library exception occurred with "Debug Assertion Failed" dialog. I am not able to find out the exact reason for this error. I am making use of Winsock API in Visual Studio Ultimate 2013. Can someone please help me to look out for a solution? Any help would be greatly appreciated!

What I have tried:

Client:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <iostream>
#include <signal.h>
#include <stdio.h>

using namespace std;

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

//DECLARATIONS
//error trapping signals
#define SIGINT 2
#define SIGKILL 9
#define SIGQUIT 3
// SOCKETS
SOCKET sock, client;

void s_handle(int s)
{
    if (sock)
        closesocket(sock);
    if (client)
        closesocket(client);
    WSACleanup();
    Sleep(10);
    cout << "EXIT SIGNAL :" << s;
    exit(0);
}


void s_cl(char *a, int x)
{
    cout << a;
    s_handle(x + 1000);
}


int main()
{
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hStdout, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
    //SetConsoleTitle(".:: Basic Echo Client By KOrUPt 07 ::. ");


    //Declarations
    DWORD poll;
    int res, i = 1, port = 999;
    char buf[100];
    char msg[100] = "";
    char ip[15];
    WSADATA data;

    signal(SIGINT, s_handle);
    signal(SIGKILL, s_handle);
    signal(SIGQUIT, s_handle);

    cout << "\t\tEcho This is a Client";

    cout << "\n\n\n\t\tEnter IP to connect to: ";
    gets(ip);

    sockaddr_in ser;
    sockaddr addr;


    ser.sin_family = AF_INET;
    ser.sin_port = htons(123);                    //Set the port
    ser.sin_addr.s_addr = inet_addr(ip);      //Set the address we want to connect to

    memcpy(&addr, &ser, sizeof(SOCKADDR_IN));

    res = WSAStartup(MAKEWORD(1, 1), &data);      //Start Winsock
    cout << "\n\nWSAStartup"
        << "\nVersion: " << data.wVersion
        << "\nDescription: " << data.szDescription
        << "\nStatus: " << data.szSystemStatus << endl;

    if (res != 0)
        s_cl("WSAStarup failed", WSAGetLastError());

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);       //Create the socket
    if (sock == INVALID_SOCKET)
        s_cl("Invalid Socket ", WSAGetLastError());
    else if (sock == SOCKET_ERROR)
        s_cl("Socket Error)", WSAGetLastError());
    else
        cout << "Socket Established" << endl;



    res = connect(sock, &addr, sizeof(addr));               //Connect to the server
    if (res != 0)
    {
        s_cl("SERVER UNAVAILABLE", res);
    }
    else
    {
        cout << "\nConnected to Server: ";
        memcpy(&ser, &addr, sizeof(SOCKADDR));
    }

    char RecvdData[100] = "";
    int ret;

    while (true)
    {
        strcpy(buf, "");
        cout << "\nEnter message to send ->\n";
        fgets(buf, sizeof(buf), stdin);


        Sleep(5);
        res = send(sock, buf, sizeof(buf), 0);

        if (res == 0)
        {
            //0==other side terminated conn
            printf("\nSERVER terminated connection\n");
            Sleep(40);
            closesocket(client);
            client = 0;
            break;
        }
        else if (res == SOCKET_ERROR)
        {
            //-1 == send error
            printf("Socket error\n");
            Sleep(40);
            s_handle(res);
            break;
        }

        ret = recv(sock, RecvdData, sizeof(RecvdData), 0);
        if (ret > 0)
        {
            cout << endl << RecvdData;
            strcpy(RecvdData, "");
        }
    }

    closesocket(client);
    WSACleanup();
}


Server:
#include <windows.h>
#include  <stdlib.h>
#include <stdio.h>
#include <winsock.h>
#include <iostream>

using namespace std;

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

// our thread for recving commands
DWORD WINAPI receive_cmds(LPVOID lpParam)
{
    cout << "thread created\r\n";

    // set our socket to the socket passed in as a parameter   
    SOCKET current_client = (SOCKET)lpParam;

    // buffer to hold our recived data
    char buf[100];
    // buffer to hold our sent data
    char sendData[100];
    // for error checking 
    int res;

    // our recv loop
    while (true)
    {
        res = recv(current_client, buf, sizeof(buf), 0); // recv cmds

        Sleep(2);

        if (res == 0)
        {
            //MessageBox(0, "error", "error", MB_OK);
            closesocket(current_client);
            ExitThread(0);
        }

        if (strstr(buf, "hello"))
        { // greet this user
            cout << "\nrecived hello cmd";

            strcpy(sendData, "hello, greetings from server\n");
            Sleep(2);
            send(current_client, sendData, sizeof(sendData), 0);
        }
        else if (strstr(buf, "bye"))
        { // dissconnected this user
            cout << "\nrecived bye cmd\n";

            strcpy(sendData, "cya\n");
            Sleep(2);
            send(current_client, sendData, sizeof(sendData), 0);

            // close the socket associted with this client and end this thread
            closesocket(current_client);
            ExitThread(0);
        }
        else
        {
            strcpy(sendData, "Invalid cmd\n");
            Sleep(2);
            send(current_client, sendData, sizeof(sendData), 0);
        }

        // clear buffers
        strcpy(sendData, "");
        strcpy(buf, "");
    }
}

int main()
{
    printf("Starting up multi-threaded TCP server");

    // our masterSocket(socket that listens for connections)
    SOCKET sock;

    // for our thread
    DWORD thread;

    WSADATA wsaData;
    sockaddr_in server;

    // start winsock
    int ret = WSAStartup(0x101, &wsaData); // use highest version of winsock avalible

    if (ret != 0)
    {
        return 0;
    }

    // fill in winsock struct ... 
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(123); // listen on telnet port 23

    // create our socket
    sock = socket(AF_INET, SOCK_STREAM, 0);

    if (sock == INVALID_SOCKET)
    {
        return 0;
    }

    // bind our socket to a port(port 123) 
    if (bind(sock, (sockaddr*)&server, sizeof(server)) != 0)
    {
        return 0;
    }

    // listen for a connection  
    if (listen(sock, 5) != 0)
    {
        return 0;
    }

    // socket that we sendrecv data on
    SOCKET client;

    sockaddr_in from;
    int fromlen = sizeof(from);

    // loop forever 
    while (true)
    {
        // accept connections
        client = accept(sock, (struct sockaddr*)&from, &fromlen);
        cout << "Client connected\r\n";

        // create our recv_cmds thread and parse client socket as a parameter
        CreateThread(NULL, 0, receive_cmds, (LPVOID)client, 0, &thread);
    }

    // shutdown winsock
    closesocket(sock);
    WSACleanup();

    // exit
    return 0;
}
Posted
Updated 11-Sep-17 0:42am
Comments
Patrice T 9-Sep-17 6:19am    
"Debug Assertion Failed" dialog
Give full error message !
apurv625 9-Sep-17 6:21am    
The error was coming because of the signal Declarations #define SIGKILL 9,
#define SIGQUIT 3. When I removed these declarations, it started working fine. Is it a good approach to remove these declarations?
Richard MacCutchan 9-Sep-17 11:41am    
No it is not a good idea. You first need to debug the application and find out the reason for the assertion.
Jochen Arndt 9-Sep-17 6:22am    
Then let the application stop and be debugged to know where it fails.

The assertion dialog contains information about the source file and line number where the assertion occured. You can open the source file to check in which function the error occured and which varaiable / parameter is invalid. Then check in your code where that function is called.

1 solution

Quote from comment:
The error was coming because of the signal Declarations #define SIGKILL 9,
#define SIGQUIT 3. When I removed these declarations, it started working fine. Is it a good approach to remove these declarations?

It looks like you have re-used some code written for Linux. Windows does not know the SIGKILL and SIGQUIT signals.

The behaviour is well explained in the documentation:
If sig is not one of the above values, the invalid parameter handler is invoked, as defined in Parameter Validation
When a C Runtime Library function detects an invalid parameter, it captures some information about the error, and then calls a macro that wraps an invalid parameter handler dispatch function, one of _invalid_parameter, _invalid_parameter_noinfo, or _invalid_parameter_noinfo_noreturn. The dispatch function called depends on whether your code is, respectively, a debug build, a retail build, or the error is not considered recoverable.

Note also that there are four errors in your code:

  1. The handler uses the global variables sock and client which are unitialised.
  2. The above mentioned global variables are never changed (always uninitialised) because you are using local variables with the same names in your main() function.
  3. You are calling the handler directly from your code which is not recommended.
  4. The handler calls functions that are not allowed to be called from a signal handler.
The points 1 and 2 does not care really because WSACleanup() will close all open sockets anyway so that the closesocket() calls can be removed.

Regarding the signal handler read the documentation:
Do not issue low-level or STDIO.H I/O routines (for example, printf or fread).

Do not call heap routines or any routine that uses the heap routines (for example, malloc, _strdup, or _putenv). See malloc for more information.

Do not use any function that generates a system call (for example, _getcwd or time).
Your code violates all of the above (not directly but all those types of functions are called behind the scenes from the functions used in the handler).

You should create two functions:
A function to be called from your code when you want to exit and a signal handler.

But I see no reason for having a signal handler here. If you want to handle Ctrl+C with Windows console applications use the SetConsoleCtrlHandler function - Windows Console | Microsoft Docs[^] instead of the signal function.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900