riting networked applications is one of the most interesting aspects of programming. It is both rewarding and intriguing to see your applications successfully communicating over the network. In this first part of a two-part series on network programming, I am going to build a chat application that works similar to MSN Messenger (or ICQ). Using the chat application, I will illustrate how network programming is done in .NET and the various challenges in building a multi-user chat application.
Figure 1 shows the application that I will build in this article.
In an article that will follow in a few weeks, I will expand on the application built in this article to provide more functionality, such as FTP, private chat, encryption, and more.
Using the TcpClient and TcpListener Classes for Network Communications
Creating a chat application generally involves socket programming, creating a connection between a client and server so that messages can be sent and received by both the client and the server. The System.Net.Sockets namespace provides the functionalities required for Socket programming. I will make use of two classes in the System.Net.Sockets namespace for this article: TcpClient and TcpListener.
|Figure 1. A Chat Ahead: The screenshot shows the completed chat application built in this article.|
The TcpClient class implements a socket for sending and receiving data using TCP. Because the connection to the remote device is represented as a stream, data can be read and written with .NET Framework stream-handling techniques.
The TcpListener class provides simple methods that listen for and accept incoming connection requests in blocking synchronous mode.
The following code example shows a very simple implementation of a server waiting for an incoming connection:
Const portNo As Integer = 500
Dim localAdd As System.Net.IPAddress = _
Dim listener As New TcpListener(localAdd, portNo)
Dim tcpClient As TcpClient = listener.AcceptTcpClient()
Dim ns As NetworkStream = tcpClient.GetStream
Dim data(tcpClient.ReceiveBufferSize) As Byte
'---read incoming stream; Read() is a blocking call---
Dim numBytesRead As Integer = ns.Read(data, 0, _
'---display data received---
Console.WriteLine("Received :" & _
Encoding.ASCII.GetString(data, 0, numBytesRead))
To connect to the server and send it a string, the client code would look like this:
Const portNo = 500
Dim tcpclient As New TcpClient
Dim ns As NetworkStream = tcpclient.GetStream
Dim data As Byte() = Encoding.ASCII.GetBytes("Hello")
'---send the text---
ns.Write(data, 0, data.Length)
|Author's Note: The NetworkStream object works with byte arrays, and hence you need to use the Encoding.ASCII.GetString() and Encoding.ASCII.GetBytes() methods from the System.Text namespace to convert the byte array to string and vice versa.
The example above is relatively simple. But the problem becomes much more pronounced when the server needs to communicate with multiple clients and be able to both send and receive messages from clients, all at the same time. To do so:
- The server must be able to create connections to multiple clients;
- The server must be able to asynchronously read data from the client and be able to send messages to the client at any time;
- The client must be able to asynchronously read data from the server and be able to send messages to the server at any time.
The rest of this article will address these three problems.