WinChat For .NET

Abstract

WinChat For .NET is a simple peer-to-peerchatting program that functions very similarly to the WinChat programprovided by Windows 2000. It provides all the functionalities that theoriginal WinChat program provides. WinChat For. NET's GUI (GraphicalUser Interface) is a bit different than the original one simply becauseof personal taste.

WinChat For .NET is based onmany basic yet powerful techniques provided by the .NET platform,including Multi-Threading, Event-Driven, Windows Form Control andSocket Programming, etc.

Download WinChat.zip

Usage of the program

You can find the WinChat.exe executable in the directory:

<Installation Dir>\WinChat For .NET\WinChat\bin\Release

WinChat For .Net Platform is based on .Netplatform beta 2 and is written in C#. You can use the program in anyway you want. However, I provide absolutely NO GUARANTEE in any sensefor this program.

 

In order to chat to a person, you haveto notify him/her before the chat can begin. The notification can bedone by typing the hostname or IP address of the workstation (where theperson is located) you want to chat into the "Remote Side's Hostname orIP Address" TextBox, and press the "Notify" button. 4 possible thingscan happen after this:


1. The called person is not involved inanother chat session and is willing to chat with you. He/She willacknowledge your notification, and the chat session can now begin;
2. The called person is not involved in another chat session, buthe/she is not willing to chat with you. He/She will acknowledge yournotification negatively. The chat session cannot begin. However, youcan try the notification again, or you can try to notify anotherperson;
3. The called person is already involved in another chat session.You will get a negative acknowledgement in this case. You have toattempt to chat with this particular person again later;
4. The remote side doesn't respond to the notification within 30seconds. You will get a time-out acknowledgement. The chatting sessioncannot begin.

If you get a positive acknowledgement from thecalled person, and want to start chatting, you can start typing yourmessage (less than 512 characters per message) in the "Type YourMessage Here" TextBox, then press the "Send" button. You will see yourmessages in the "Your Message" TextBox, and the called person'smessages in the "Remote Side's Message" TextBox.

After the chatting is done, either side canterminate the call by pressing the 'Hangup" button. After that, bothsides can start another chat session with any other person.

When you are finished using this program, you can exit the program by pressing the "Exit" button.

Basic Architecture of the program

The whole architecture of WinChat For .NET is very simple. All it involves is 3 classes:

1. TcpUdpServer — handles all the server functionalities like listening to connections and receiving messages;
2. TcpUdpClient — handles all the client functionalities including call request and call initiation;
3. WinChatFormLibrary — handles all the Windows Form Controls, andalso acts as a middle agent for the communication between TcpUdpClientand TcpUdpServer.

This project makes heavy use of theMulti-Threading, Delegate and Socket programming techniques incommunication. It also depends on some protocol-like handshakes tosetup the chatting sessions. Fig. 1 depicts the procedures a call isset-up.

When either side of the party wants toinitiate a call request, the following procedures will take placebefore both parties can start the chat session.

1. The calling side gives the remote side's (called side's) hostname to the WinChatFormLibrary and press the "Notify" button;
2. The calling side's TcpUdpClient sends the "Notify Request" to the called side's TcpUdpServer;
3. The called side's TcpUdpServer returns the "Notify Accept" message back to the calling side;
4. The calling side's TcpUdpClient sets up a TCP connection to the called side's TcpUdpServer;
5. The calling side's TcpUdpClient notifies its own TcpUdpServerthat it is already involved in a chat session (through raising anevent), so that the TcpUdpServer will reject all the additional callrequests until this on-going call ends;
6. The called side's TcpUdpServer notifies its ownWinChatFormLibrary that a call has been setup from the calling side(through raising an event);
7. A delegate function in the called side's WinChatFormLibrary is invoked by the call initiation event;
8. The called side's TcpUdpClient, invoked by the delegate functionin its own WinChatFormLibrary, will setup a TCP connection to thecalling side's TcpUdpServer based on the hostname obtained from theTcpUdpServer.It is noteworthy that two TCP connections are created for a call, onefor each direction. I could have done it with only one connection for acall, but I chose this way. The reason is that the architecture of theprogram contains one client and one server that are quite independentto each other, I feel that it's more logical to have both sides (thecalling and the called sides) do similar things to each other (kind oflike a mirror to each other). Thus, I decided to have each side createone TCP connection to the other.

Fig. 2 depicts the procedures a call is terminated.

When either side wants to terminate the call,the following procedures will take place (Note: either the calling sideor the called side can terminate the call at any time):


1. When the terminating side wants toterminate an on-going call, he/she will press the "Hangup" button inthe WinChatFormLibrary;
2. The terminating side's TcpUdpClient will send a "Notify Hang-up Request" message to the terminated side's TcpUdpServer;
3. The terminated side's TcpUdpServer will reply with a "Notify Hang-up Accept" message to the terminating side's TcpUdpClient;
4. The terminating side's TcpUdpClient will send a TCP message"Notify Last Message" to the terminated side's TcpUdpServer, so thatthe terminated side's TcpUdpServer will close the TCP socket for thisconnection;
5. The terminating side's TcpUdpClient will now close the TcpClient's socket;
6. The terminating side will notify its own TcpUdpServer (throughraising an event) that the on-going call has ended, so that theTcpUdpServer can accept incoming call requests;
7. The terminated side's TcpUdpServer will notify theWinChatFormLibrary that the terminating side has already ended theon-going call (through raising an event);
8. A delegate function in the WinChatFormLibrary will be invoked by the call termination event;
9. The terminated side's TcpUdpClie

nt, invo
ked by the delegatefunction in its own WinChatFormLibrary, will send the TCP message"Notify Last Message" to the terminating side's TcpUdpServer, so thatthe terminating side's TcpUdpServer will close the TCP socket for thisconnection;
10. The terminated side's TcpUdpClient will now close the TcpClient's socket;

Thus, the call setup and termination caneasily be handled by a few very simple steps based on the Socket andDelegate facilities provided by the .NET architecture. It's noteworthythat, although the above steps are described in procedural form, someof the steps actually happen simultaneously.

A few points to discuss

In this simple project, I have made use of only a few namespaces:

 

System.Windows.Forms;
System.Net.Sockets;
System.Threading;
System.Timers;

I found that these namespaces really make theproject much simpler than it would have been if it is done in C++. Inaddition, the delegate concept also makes the event-driven model mucheasier to handle than C++.

Most of the program flow and techniques usedare already documented inside the code as comments. However, there area few points that I think will be worth discussing here.

First of all, I think the System.Net.Socketsprovides a lot of great classes that make the Socket programming a joyto work with, especially the TcpListener, TcpClient and UdpClientclasses. They take care of most of the low-level socket programmingunder the hood and make their operation transparent to the client code.For example, to create a TCP server and make it listen to the portTCP_PORT, all I have to do is only 1 line of code:

TcpListener tcpListener = new TcpListener(TCP_PORT).

And to create a TCP client and make aconnection to the TCP server SERVER_NAME at TCP_PORT, again, 1 line ofcode will do the job:

TcpClient tcpClient = new TcpClient(SERVER_NAME, TCP_PORT).

Although all these classes still perform thetraditional socket operations under the hood, hiding all of them fromthe client application does help simplify the overall programstructure. However, for those programmers who are familiar with Winsockprogramming, I still suggest to use the traditional Socket classbecause it's still more powerful then these "convenient" siblings.

Second, this project has made use of theMulti-Threading facilities provided by the .NET platform. The UDPserver and the TCP server are running on different threads so that theycan receive and process incoming messages simultaneously. The followingcode segments show how the TCP and UDP threads can be started andaborted:

public void start_servers()
{
//Starting the TCP Listener thread (StartListen).
sampleTcpThread = new Thread(new
ThreadStart(this.StartListen));

sampleTcpThread.Start();

//Starting the UDP Notify thread (receiveNotify).
udpNotifyThread = new Thread(new
ThreadStart(this.receiveNotify));

udpNotifyThread.Start();
}

To start the server threads:

start_servers();

To abort them:

sampleTcpThread.Abort();
udpNotifyThread.Abort();

This is it! Of course, you might want to add some try/catch blocks to handle some exceptions that might happen in the codes.

The third thing that I want to discuss is thedelegate model of event handling. In this project, there are quite afew places that I can make use of delegates. For example, in Fig 1,step 6, after the calling side connects to the called side'sTcpUdpServer, the TcpUdpServer will raise an event. The event will thencall the delegate defined in the WinChatFormLibrary class, which will,through the TcpUdpClient, make a connection to the calling side'sTcpUdpServer. Here is the code segment that does what I described.

In WinChatFormLibrary class, we first have to make the TcpUdpServer listen to the event peerNotify():

TcpUdpServer.peerNotify += new
TcpUdpServer.NotificationHandler(this.OnPeerNotify);

Defining the OnPeerNotify delegate (with most details deleted):

public void OnPeerNotify()
{
this.tcpUdpClient.createTcpClientConnection(remoteHostName};
}

In the TcpUdpServer, all we have to do is tocall the event peerNotify() when it receives a connection from theremote peer. And it's done!

Last but not least, I also want to brieflymention the timer handling in the .NET platform. I have made use of afew timers in this project. To start a timer, all I have to do is just2 steps:

1. Add the event listener to the code where you want to start the timer:

receiveNotifyTimer = new
System.Timers.Timer(30000);
receiveNotifyTimer.Elapsed += new
ElapsedEventHandler(this.OnTimedEvent);

2. Define the delegate OnTimeEvent():

public void OnTimedEvent1(object source, ElapsedEventArgs e)
{
//Do something when the timer expires.
}

And stopping a timer is just a matter of calling someTimer.Stop(). That's it!!

Conclusion

I have used WinChat in some occasions before,and thought that it might be a good starting point to learn C# byrewriting this little utility with it. I hope this program will beuseful for someone who needs it, or at least useful as a learning tool.

Many articles I have read in these few monthshave compared C# to Java or C++ regarding to the easiness of writinguseful programs, I am getting very curious about this language. Afterwriting C# codes for a while (basically since Beta 2 was released), Iam following in love with it. The class library is incredibly useful.And learning to write codes with this totally new language is really ajoy ride. Although the performance is still an issue that Microsoft hasto figure out before the final release, I think the Beta 2 release isalready pretty close to what a next generation language ought to belike.

This is the first serious project that I havewritten in C#. Although I have tried my best to QA the program myself,it's still bound to be buggy. Please let me know of any bugs, and anysuggestions you have for me to improve the program.

Finally, I have to thank many people from thedotnet discussion group and the dotnet newsgroup who have answered manyof my questions. Those answers are really helpful, and they really easemy .NET learning in many ways.

Thanks very much in advance for any suggestion you have for me. I can be contacted at pakkit@yahoo.com.

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!