Chat Application In Managed C++

The following program is a dialog based application, which works both as a client and a server. We can send messages to both the client and the server. First we will run it as a server connected to a desired port and then as a client. We plan to design our dialog application like this.

One major disadvantage of Managed C++ is the absence of the Resource Editor. Due to this difficulty we always have to wirte the full code to create a dialog and its components. To create our dialog box we have to write the code as shown below. Following is the class which represents our form i.e the dialog. The �gc keyword that preceeds the class name declares a garbage-collected object.

__gc class WinForm: public Form

{

public:

Label *label3 ;

ListBox *rmessage ;

GroupBox *groupBox3 ;

GroupBox *groupBox2 ;

ListBox *smessage ;

Button *sendbut ;

TextBox *message ;

RadioButton *crad ;

RadioButton *srad ;

GroupBox *groupBox1 ;

Button *conbutton ;

TextBox *port ;

Label *label2 ;

TextBox *sname ;

Label *label1 ;

Socket *s ;

Stream *st ;

void conbutton_Click ( Object *sender, System::EventArgs* e ) ;

void sendbut_Click ( Object *sender, System::EventArgs* e ) ;

WinForm( )

{

InitForm( ) ;

}

void Dispose( )

{

// Form is being destroyed. Do any necessary clean-up here.

s -> Close( ) ;

st -> Close( ) ;

Form::Dispose( ) ;

}

void InitForm( )

{

rmessage = new ListBox( ) ;

groupBox1 = new GroupBox( ) ;

port = new TextBox( ) ;

smessage = new ListBox( ) ;

label2 = new Label( ) ;

label3 = new Label( ) ;

label1 = new Label( ) ;

sname = new TextBox( ) ;

conbutton = new Button( ) ;

groupBox2 = new GroupBox( ) ;

groupBox3 = new GroupBox( ) ;

crad = new RadioButton( ) ;

sendbut = new Button( ) ;

message = new TextBox( ) ;

srad = new RadioButton( ) ;

////form

System::Drawing::Size s ;

s.Height = 400 ;

s.Width = 400 ;

ClientSize = s ;

Point p ;

p.X = 264 ;

p.Y = 48 ;

Text = "Chat" ;

//rmessage

p.X = 18 ;

p.Y = 22 ;

s.Width = 312 ;

s.Height = 69 ;

rmessage -> Location = p ;

rmessage -> Size = s ;

rmessage -> TabIndex = 10 ;

//groupbox1

p.X = 16 ;

p.Y = 8 ;

s.Width = 88 ;

s.Height = 72 ;

groupBox1 -> Location = p ;

groupBox1 -> TabIndex = 5 ;

groupBox1 -> TabStop = false ;

groupBox1 -> Text = "Connect As" ;

groupBox1 -> Size = s ;

//port

p.X = 200 ;

p.Y = 48 ;

s.Width = 56 ;

s.Height = 20 ;

port -> Location = p ;

port -> TabIndex = 3 ;

port -> Size = s ;

//smessage

p.X = 32 ;

p.Y = 144 ;

s.Width = 312 ;

s.Height = 69 ;

smessage -> Location = p ;

smessage -> Size = s ;

smessage -> TabIndex = 8 ;

//label2

p.X = 128 ;

p.Y = 48 ;

s.Width = 40 ;

s.Height = 16 ;

label2 -> Location = p ;

label2 -> Text = "Port" ;

label2 -> Size = s ;

label2 -> TabIndex = 2 ;

///label3

p.X = 16 ;

p.Y = 96 ;

s.Width = 48 ;

s.Height = 23 ;

label3 -> Location = p ;

label3 -> Text = "Message" ;

label3 -> Size = s ;

label3 -> TabIndex = 12 ;

//label1

p.X = 128 ;

p.Y = 16 ;

s.Width = 72 ;

s.Height = 16 ;

label1 -> Location = p ;

label1 -> Text = "Server Name" ;

label1 -> Size = s ;

label1 -> TabIndex = 0 ;

// sname

p.X = 200 ;

p.Y = 16 ;

s.Width = 120 ;

s.Height = 20 ;

sname -> Location = p ;

sname -> TabIndex = 1 ;

sname -> Size = s ;

//conbutton

p.X = 264 ;

p.Y = 48 ;

s.Width = 56 ;

s.Height = 23 ;

conbutton -> Location = p ;

conbutton -> Size = s ;

conbutton -> TabIndex = 4 ;

conbutton -> Text = "Connect" ;

conbutton -> add_Click ( new EventHandler ( this,

&WinForm::conbutton_Click ) ) ;

//groupbox2

p.X = 16 ;

p.Y = 128 ;

s.Width = 344 ;

s.Height = 96 ;

groupBox2 -> Location = p ;

groupBox2 -> TabIndex = 9 ;

groupBox2 -> TabStop = false ;

groupBox2 -> Text = "Send" ;

groupBox2 -> Size = s ;

///groupbox3

p.X = 16 ;

p.Y = 232 ;

s.Width = 344 ;

s.Height = 104 ;

groupBox3 -> Location = p ;

groupBox3 -> TabIndex = 9 ;

groupBox3 -> TabStop = false ;

groupBox3 -> Text = "Recieved" ;

groupBox3 -> Size = s ;

//crad

p.X = 16 ;

p.Y = 40 ;

s.Width = 56 ;

s.Height = 16 ;

crad -> Location = p ;

crad -> Text = "Client" ;

crad -> Size = s ;

crad -> TabIndex = 1 ;

//sendbut

p.X = 288 ;

p.Y = 96 ;

s.Width = 75 ;

s.Height = 23 ;

sendbut -> Location = p ;

sendbut -> Size = s ;

sendbut -> TabIndex = 7 ;

sendbut -> Text = "Send" ;

sendbut -> add_Click ( new EventHandler ( this,

&WinForm::sendbut_Click ) ) ;

///message

p.X = 72 ;

p.Y = 96 ;

s.Width = 208 ;

s.Height = 20 ;

message -> Location = p ;

message -> TabIndex = 6 ;

message -> Size = s ;

///srad

p.X = 16 ;

p.Y = 16 ;

s.Width = 56 ;

s.Height = 23 ;

srad -> Location = p ;

srad -> Text = "Server" ;

srad -> Size = s ;

srad -> TabIndex = 0 ;

srad -> Checked = true ;

groupBox3 -> Controls -> Add ( this -> rmessage ) ;

groupBox1 -> Controls -> Add ( this -> crad ) ;

groupBox1 -> Controls -> Add ( this -> srad ) ;

Controls -> Add ( label3 ) ;

Controls -> Add ( smessage ) ;

Controls -> Add ( sendbut ) ;

Controls -> Add ( message ) ;

Controls -> Add ( groupBox1 ) ;

Controls -> Add ( conbutton ) ;

Controls -> Add ( port ) ;

Controls -> Add ( label2 ) ;

Controls -> Add ( sname ) ;

Controls -> Add ( label1 ) ;

Controls -> Add ( groupBox2 ) ;

Controls -> Add ( groupBox3 ) ;

}

} ;

We wrote all the initailizations in a function called InitForm( ) which we have called in the constructor of our form class . This is how the form should now look (this will be visible only when we compile it, now we still have to add handlers so we will not compile it right now ).

Next we added two data members Viz:

Socket s ;

Stream st ;

We will have to add two events viz: conbutton_Click( ) and sendbut_Click( ) for the Connect and Send Buttons respectively. The Connect button will make the application work as a client or server according to the selection made.

void WinForm::conbutton_Click(Object *sender, System::EventArgs *e)

{

String *servername = sname -> Text ;

int *portno ;

int x = port -> Text -> ToInt32( ) ;

portno = &x ;

if ( srad -> Checked )

{

TCPListener *tcpl = new TCPListener ( x ) ;

tcpl -> Start( ) ;

s = tcpl -> Accept( ) ;

recvserverthread *r = new recvserverthread ( s, rmessage);

ThreadStart *ts = new ThreadStart ( r,

&recvserverthread::myfunc ) ;

Thread *t = new Thread ( ts ) ;

t -> Start( ) ;

}

else

{

TCPClient *tcpc = new TCPClient( ) ;

if(DNS::GetHostByName(servername ) -> Hostname == "" )

{

MessageBox::Show ( "can't Connect to Server" ) ;

return ;

}

tcpc -> Connect ( servername, x ) ;

st = tcpc -> GetStream( ) ;

recvclientthread *r = new recvclientthread ( st, rmessage ) ;

Thread *t = new Thread ( new ThreadStart (r,

&recvclientthread::myfunc ) ) ;

t -> Start( ) ;

}

}

If the Checked property of srad is true then the TCPListener class is used for server. The Start( ) method of the TCPListener class starts listening to network requests. The Accept( ) method accepts a pending connection request. Next the receiving of messages is started on another thread.

If the Checked property of srad is not true the TCPClient class is used for client. The GetHostByName( ) method retrieves a string representing the DNS name of the host. If the name is null, the application stops. If not, the client is connected using the Connect( ) method. The Connect( ) method connects the client to a TCP host. The GetStream( ) method returns the stream used to write data to the remote host. The receiving of messages is then started on a different thread.

The sendbut_Click( ) event looks like this:

void WinForm::sendbut_Click(Object *sender, System::EventArgs *e)

{

Byte bstr[ ] = Encoding :: ASCII-> GetBytes ( message -> Text);

if ( srad -> Checked )

s -> Send ( bstr, bstr.Length, 0 ) ;

else

st -> Write ( bstr, 0, bstr.Length ) ;

smessage -> Items -> Add ( message -> Text ) ;

message -> Text = "" ;

}

If the application is running as a server we use the Send( ) method of the Socket class, which sends data connected to a socket. If it is running as a client we use the Write( ) method of the Stream class, which writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. This message is then added to the �Sent� ListBox.

To receive messages we wrote two classes viz: - the recvclientthread class and the recvserverthread class for the client and server respectively. These two classes will take care of starting the threads receiving the messages. The code for both the classes is as follows:

__gc class recvclientthread

{

Stream *s ;

ListBox *l ;

public:

recvclientthread ( Stream *ss, ListBox *ll )

{

s = ss ;

l = ll ;

}

void myfunc( )

{

Byte bstr[] = new Byte[32] ;

while ( true )

{

s -> Read ( bstr, 0, bstr.Length ) ;

String *str = Encoding :: ASCII -> GetString ( bstr ) ;

l -> Items -> Add ( str ) ;

}

}

};

__gc class recvserverthread

{

private:

Socket *s ;

ListBox *l ;

public:

recvserverthread( Socket *ss, ListBox *ll )

{

l = ll ;

s = ss ;

}

void myfunc( )

{

while ( true )

{

Byte bstr[] = new Byte[32] ;

s -> Receive ( bstr, bstr.Length, 0 ) ;

String *str = Encoding :: ASCII -> GetString ( bstr ) ;

l -> Items -> Add ( str ) ;

}

}

};

To receive a message in the client we use the Stream class. The Read( ) method of the Stream class reads a sequence of bytes from the current stream and advances the current position within the stream by the number of bytes read. This stream is converted into a string using the Encoding::ASCII -> GetString( ) method and added to the ListBox using the Items->Add( ) method.

To receive a message in the server we use the Socket class. The Receive( ) method of the Socket class receives data from a connected socket. This data is converted into a string and added to the ListBox.

Your Title