Multiple Clients Chat Application - I


In this article we would create a chat server and client applications using sockets. The chat server has the following capabilities:

(a) The server can connect to the multiple clients.

(b) The server allows all-to-all communication.

(c) If a new client joins, all the old clients get informed about his arrival whereas the new client gets the list of all the old

clients.

(d) If a client quits all the existing clients get informed.

Create a dialog-based application 'ChatServer'. While creating the application check the 'Windows Sockets' check box in 'Step 2 of 4' of the AppWizard. Add controls to the dialog template as shown in the following figure:


Add variables to the controls as shown in the following table:

Control

Variable

Type

Category

Port edit box

m_port

int

Value

Message edit box

m_message

CString

Value

Sent list box

m_sent

CListBox

Control

Received list box

m_recvd

CListBox

Control

Send button




Listen button

m_listen

CButton

Control

The user would enter the port number (any integer) and click on the 'Listen' button. Once a client gets connected to the server the user can send messages to the client by entering the message in the 'Message' edit box and clicking on the 'Send' button. The messages sent by the server would be listed in the 'Sent' list box whereas messages received would be listed in the 'Received' list box.

Insert a class 'mysocket' derived from the CSocket class. Add a member function setparent( ) to the mysocket class. Add the following code in the setparent( ) function:

void mysocket::setparent ( CDialog *pd )

{

m_pdialog = pd ;

}

The setparent( ) function accepts the pointer to the application dialog using which we can access the member functions of the dialog class from the mysocket class. We have stored this pointer in m_pdialog data member of mysocket class. Declare m_pdialog as the pointer to the CDialog class.

Override the virtual member functions of CSocket class OnAccept( ) and OnReceive( ) in the mysocket class. Write the code in these functions as shown below:

void mysocket::OnAccept ( int nErrorCode)

{

if ( nErrorCode == 0 )

( ( CChatServerDlg* ) m_pdialog ) -> onaccept( ) ;

CSocket::OnAccept ( nErrorCode ) ;

}

void mysocket::OnReceive ( int nErrorCode )

{

if ( nErrorCode == 0 )

( ( CChatServerDlg* ) m_pdialog ) -> onreceive ( this ) ;

CSocket::OnReceive ( nErrorCode ) ;

}

From the OnAccept( ) and OnReceive( ) functions we have called the onaccept( ) and onreceive( ) member functions of the dialog class respectively. To the onreceive( ) function we have passed the pointer to the socket from which we have received the message.

We will see the onaccept( ) and onreceive( ) functions later on. First call the setparent( ) function from CChatServerDlg::OnInitDialog( ) function as shown below:

m_listensocket.setparent ( this ) ;

Add m_listensocket as a private data member of type mysocket to the dialog class.

Add a handler for the 'Listen' button to the CChatServerDlg class. The OnListen( ) handler is given below:

void CChatServerDlg::OnListen( )

{

UpdateData ( TRUE ) ;

m_listensocket.Create ( m_port ) ;

m_listensocket.Listen( ) ;

m_listen.EnableWindow ( FALSE ) ;

}

Here, we have retrieved the port entered by the user by calling UpdateData( ) function. We have created the socket by calling mysocket::Create( ) function. We have passed the port number to the Create( ) function. Next, we have called mysocket::Listen( ) function to listen for incoming connection requests by client. We have disabled the 'Listen' button by calling EnableWindow( ) function so that the user would not click it again.

Add the onaccept( ) function to the dialog class. The function is given below:

void CChatServerDlg::onaccept( )

{

clientinfo *pcinfo = new clientinfo ;

m_listensocket.Accept ( pcinfo -> socket ) ;

pcinfo -> socket.setparent ( this ) ;

m_clientlist.AddTail ( pcinfo ) ;

}

We would see the working of the onaccept( ) function next week.

No comments: