Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Barry's Chat System

0.00/5 (No votes)
24 Nov 2002 2  
Barry's Chat System

Sample Image - BarrysChatSystem.gif

Introduction

This article demonstrates the technique of creating a chat system. The article contains a chat server and a chat client, each performs different tasks and cannot be used interchangeably. Both client and server use Windows sockets for the purpose of connecting and sending lines of text between themselves. You can use the server and client either on your machine or over a private LAN or network to chat.

NOTE: I do not have access to either a LAN or network, hence this software was only tested in "local loop" on my machine, anyone testing the software over a network can please send the test results through E-Mail to me.

How to use

Preparing to use ChatServer & ChatClient

  • Download the ChatServer & ChatClient source code
  • Unzip ChatServer & ChatClient source code
  • Start Visual Studio
  • Build the ChatServer & ChatClient executables
  • Exit Visual Studio

To use the ChatServer and ChatClient on your machine in what is know as "Local Loop", do the following:

Starting ChatServer

  • Start ChatServer (executable is in ChatServer\Debug folder)
  • Keep the port no. 0 and click Ok (note: if you change the port no. the same no. must be used when connecting through ChatClient)
  • Port no. can be between 0 to 1499 (this is useful in cases where the port no. is in use by another application on the server system
  • Note: Even though the port no. input is 0, it is in reality 1500 + x (x stands for the port no. input by you, 0 in this case)

Starting ChatClient

  1. Start ChatClient (executable is in ChatClient\Debug folder)
  2. From the menu, select Connection->Connect (or click on the Connect button)
  3. Logon form will be displayed
  4. In the server box type 127.0.0.1
  5. In the nickname box type any name (should be different for each invocation of ChatClient)
  6. In the port no. box type 0 (remember we had started the ChatServer with 0 as port no.)
  7. Click Ok
  8. Repeat steps 1 thru 7 above to start another ChatClient but with a different nickname. You can start as many ChatClients as you want, restricted by available memory.
  9. Chat to your hearts content, with yourself of course.

To use ChatServer and ChatClient on a network do the following, carry out the steps in the "Preparing to use ChatServer & ChatClient" above.

  • Copy ChatServer executable on a server system
  • Copy ChatClient executables on machines from where you want users to chat
  • Start ChatServer on the server system, refer the "Starting ChatServer" section above
  • Start ChatClient on the machines where the ChatClients were copied, refer the "Starting ChatClient" section above, but remember, in the server box on the logon form, you have to type the name or IP address of the server system on which the ChatServer is running (not 127.0.0.1) and port no. as applicable

Caution

If you copy ChatServer and ChatClient executables on machines that do not have Visual Studio setup, the executables may not run since MFC is not installed by default on the Windows operating system.

If the installable versions of ChatServer and ChatClient are available for download in the download section at the top, you can install both on any machine running Windows 9x /Windows 2000 / Windows XP, since the Installable versions have MFC included.

I may not upload the installable versions at present because of their huge size (1.2Mb each) and to be very frank I cannot afford it at present, maybe over a period of time, if there is demand for the same.

What's missing

  • No colored text for chatting
  • No variable fonts for chatting
  • Single chat room
  • No threads used in the source

Maybe in a later version the above could be incorporated, presently under testing.

Note for developers

Most important code for both the server and client is in the classes CChatServerDoc and CChatClientDoc, you would well concentrate on these two classes.

A CObject class named CMsg is used in both server and client to send and receive messages back and forth, which are then unassembled by the receiver (server or client). CMsg class has the following members:

  • Code (to indicate the type of message)
  • m_strText (message text)
  • m_bClose (sent when the client is disconnecting or shutting down)

Following is a list of codes sent by both server and client (you can have your own codes as the need maybe):

#define JOINING_CHAT          1
#define LEAVING_CHAT          2
#define SENDING_CHATTERS_LIST 3
#define SENDING_NICKNAME      4
#define NORMAL_MESSAGE        5
#define DUPLICATE_NICKNAME    6

How it works

After you start the server by inputting port no. and clicking Ok, a socket is created for listening for incoming connect request, using the following code in the member function OnNewDocument()

m_pSocket = new CListeningSocket(this);
if (m_pSocket->Create(Dialog.m_nPort+1500))
{
    if (m_pSocket->Listen())
        return TRUE;
}

When a new connect request is received from a client, the member function OnAccept in the class CListeningSocket is notified by the system. OnAccept then calls ProcessPendingAccept function in class CChatServerDoc as show below:

void CListeningSocket::OnAccept(int nErrorCode)
{
    CSocket::OnAccept(nErrorCode);
    m_pDoc->ProcessPendingAccept();
}

In the ProcessPendingAccept function, a new socket (CClientSocket) is created for the new client and the created socket is added to the pointer list CPtrList, which is a kind of array. We use the pointer list all throughout the program to retrieve the socket for sending or receiving messages. The system then reads the incoming message in the member function OnReceive in the CClientSocket which in turn calls ProcessPendingRead sending to it the client socket, which sends the message, as shown below:

void CClientSocket::OnReceive(int nErrorCode)
{
     CSocket::OnReceive(nErrorCode);
     m_pDoc->ProcessPendingRead(this);
}

Inside ProcessPendingRead the CMsg object sent by the client is unassembled and based on Code of the message, action is taken as appropriate.

When a client disconnects or exits by selecting from menu, File->Exit, a message is sent to the server with m_bClose set to TRUE. Server receives the message and closes the client socket as shown below:

void CChatServerDoc::CloseSocket(CClientSocket* pSocket)
{
    // Close the Client Socket

    pSocket->Close();
    POSITION pos,temp;
    for(pos = m_connectionList.GetHeadPosition(); pos != NULL;)
    {
        temp = pos;
        // Search for the Socket in the Pointer List

        CClientSocket* pSock = 
           (CClientSocket*)m_connectionList.GetNext(pos);
        if (pSock == pSocket)
        {
            // Found it , so remove it from the Pointer list

            // so that no more messages are sent to that Client Socket

            m_connectionList.RemoveAt(temp);
            break;
        }
    }
    UpdateConnections();
    delete pSocket;
    if(m_connectionList.GetCount() == 0)
        m_msgList.RemoveAll();
}

If you exit the server by selecting from the menu, File->Exit, and if there are clients connected, all the clients are notified by the server that it has shut down and all the CClientSocket(s) are closed. This also prevents the clients from crashing. Following is the code which carries out the task of closing the client sockets.

void CChatServerDoc::DeleteContents()
{
     // You must initilize m_pSocket to NULL in the Constructor of 

     // CChatServerDoc else the server will crash at the start

     if(m_pSocket == (CListeningSocket*)NULL)
        return;

    // Delete the Listening Socket

    delete m_pSocket;
    m_pSocket = NULL;
    
    CString temp;
    if (temp.LoadString(IDS_SERVERSHUTDOWN))
        m_msgList.AddTail(temp);

    while(!m_connectionList.IsEmpty())
    {
     // Get a Pointer to the Client Socket

      CClientSocket* pSocket = 
        (CClientSocket*)m_connectionList.RemoveHead();
      CMsg* pMsg = AssembleMsg(pSocket , NORMAL_MESSAGE);
      //Set Code for Closing

        pMsg->m_bClose = TRUE;
      // Send Server ShutDowm message to the Client

      SendMsg(pSocket, pMsg);

      if (!pSocket->IsAborted())
      {
         // ShutDown the Client

         pSocket->ShutDown();
         BYTE Buffer[50];
         while (pSocket->Receive(Buffer,50) > 0);
         // Delete the Client Socket

         delete pSocket;
      }
   }

   m_msgList.RemoveAll();

   if (!m_viewList.IsEmpty())
      Message("");

   CDocument::DeleteContents();
}

Have fun, chat to your heart's content, but don't blame me. I developed this by modifying MSDN Sample Chatter & Chatsvr for fun sake.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here