Tuesday, August 20, 2013

Threaded multi chat room server source code in c++ with MFC Part - 1

Multi-client chat server is open source as I have created it. In this server multiple user can log in and communicate with one another as multicast user. In reality it can use as a chat room server. Can be modified as peer to peer (p2p) text chat. It can also be used as a backbone of a video conferencing project. It has a beautiful and easy to use user interface in MFC. This project is compatible with Microsoft visual studio 2010. I will describe the use of class and function with source code.




Technology used:

i.   C++
ii.   Microsoft visual Studio 2010
iii.  MFC GUI
iv.  Winshock2 Socket
v.   TCP/UDP
vi.  Windows Thread


This project consist of  3 classes.

1. Server.cpp
2. ServerDlg.cpp
3. ServerManager.cpp


Lets start with core portion -- I mean the network level connection portion.

I have used the Winshock2 library for the purpose of network communication.

You can use this library on windows  with MVS 2010 by including library --

# include <winsock2.h>

And as it is multi user  and have GUI so we need thread. For this I have used Windows thread.
You can use this windows thread just by adding ---

# include <Windows.h>

So,  why we are late. Lets start....


ServerManager.cpp  -- core network connection class. In that class I have also demonstrate how to fetch the remote client IP address from a socket connection.


void ServerManager::StartListening(int iPort)
{
    iCount=0;
printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        return;
    }
    
    printf("Initialised.\n");
    
    //Create a socket
    if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d" , WSAGetLastError());
        m_pDialog->ShowServerInfo("Could not create socket");
    }

    printf("Socket created.\n");
    
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( iPort );
    
    //Bind
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed with error code : %d" , WSAGetLastError());
        m_pDialog->ShowServerInfo("Bind failed with error code");
        exit(EXIT_FAILURE);
    }
    
    puts("Bind done");

    //Listen to incoming connections
    listen(s , 100);
     char *message;
     puts("Waiting for incoming connections...");
     m_pDialog->ShowServerInfo("Waiting for incoming connections...\n");
     c = sizeof(struct sockaddr_in);
    
    while( (new_socket = accept(s , (struct sockaddr *)&client, &c)) != INVALID_SOCKET )
    {
        puts("Connection accepted");
      
        socklen_t len;
        struct sockaddr_storage addr;
        char ipstr[INET6_ADDRSTRLEN];
        int port;

        len = sizeof addr;
        getpeername(new_socket, (struct sockaddr*)&addr, &len);

        // deal with IPv4:
        if (addr.ss_family == AF_INET) {
            struct sockaddr_in *s = (struct sockaddr_in *)&addr;
            port = ntohs(s->sin_port);
            inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
        }

        printf("Peer IP address: %s\n", ipstr);
        m_pDialog->ShowServerInfo("Connected Peer IP address: "+string(ipstr)+"\n");
        CWinThread *cTh = AfxBeginThread(
        DataThreadFunc,
        (LPVOID)new_socket);
        ++iCount;
        sArray[iCount] = new_socket;
    }
    
    if (new_socket == INVALID_SOCKET)
    {
        printf("accept failed with error code : %d" , WSAGetLastError());
        return;
    }
}
StartListening(int iPort) Initiate a socket and Start listening on a particular port for incoming connections.

This bold letter means it can accept multiple connection( client ). In that function we used a static global variable to count the connection globally and a global static SOCKET array to stored the socket's pointer for future use from thread.

How ?

You can see on that function I have used windows thread. Here I accept the incoming connection and make a thread for every connection.

You can see that with the function --


UINT __cdecl ServerManager::DataThreadFunc(LPVOID pParam)
{
    SOCKET pYourSocket = reinterpret_cast<SOCKET>(pParam);
  
    char *message;
    message = "Welcome to Matrix chat room.\n";
    send(pYourSocket , message , strlen(message) , 0);
    char server_reply[2000];
    int recv_size;

    while((recv_size = recv(pYourSocket , server_reply , 2000 , 0)) != SOCKET_ERROR)
    {
        server_reply[recv_size] = '\0';
         for(int i = 1;i<=iCount; i++)
        {
            if( send(sArray[i] , server_reply, recv_size , 0) < 0)
            {
                puts("Send failed");
             }
        }

    }
    return 0;
}
In DataThreadFunc(LPVOID pParam) I have used the winshock send() API to sending the welcome to the client by client socket.
Here I also have a while loop with recv() API which continue to listening for client messages.
This is a static function which is called for every incoming connection for 1 time.

After receiving a message from a client this thread server now sends this message to every socket it has on its SOCKET array by fetching the socket.

NOTE :  Any smart mind can modified this function and can use for p2p message chat.


COMPLETE CODE


 NEXT



4 comments:

  1. Hello Admin. Please send for me code socket this. Because link download dje. Thank
    My email: nguyenlinh20687@gmail.com

    ReplyDelete
    Replies
    1. There it is -- https://github.com/robelsharma/MultiClientChatRoom

      Delete
  2. Hi Robel, I couldn't find Server.exe, can you send me?

    ReplyDelete
    Replies
    1. Here is the github link for binary --
      https://github.com/robelsharma

      Delete

How to enable hotspot in TPG iPhone

 By default, the hotspot does not work on the phone. It will ask you to contact the provider. This video will help you bypass the network ...