In this article I will be showing you how to create a client for our chat application. This is part two of the series, so if you haven’t read part one yet please do so before continuing with this article as it explains the infrastructure of the whole application. You can read part one here: C# Chat Application Over Asynchronous UDP Sockets – Part 1, The Server.
The Client
For our client to connect to the server, which is listening for incoming connections, the server must obviously be running
. Apart from that, the client must know the IP address of the server and which port the server is listening on. We already know from part one of this article series that the server is listening on port 30,000. However we don’t know the server’s IP address so that will have to be input manually from the user interface of the client.
The client will make use of the exact same Packet class we used for the server. In fact this class could have been placed into a library and included into each project as a dll instead of replicating the code twice… but it makes no difference for the purpose of this example, plus I didn’t feel like creating a dll
.
Anyway, our client looks something like this:

As can be seen in the above screenshot, there is a section where the user must input a user name and a server IP address. Once this is done the user must click the connect button to let the server know that a client is connecting. The connect code is shown below:
private void btnConnect_Click(object sender, EventArgs e)
{
try
{
this.name = txtName.Text.Trim();
// Initialise a packet object to store the data to be sent
Packet sendData = new Packet();
sendData.ChatName = this.name;
sendData.ChatMessage = null;
sendData.ChatDataIdentifier = DataIdentifier.LogIn;
// Initialise socket
this.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// Initialise server IP
IPAddress serverIP = IPAddress.Parse(txtServerIP.Text);
// Initialise the IPEndPoint for the server and use port 30000
IPEndPoint server = new IPEndPoint(serverIP, 30000);
// Initialise the EndPoint for the server
epServer = (EndPoint)server;
// Get packet as byte array
byte[] data = sendData.GetDataStream();
// Send data to server
clientSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, epServer, new AsyncCallback(this.SendData), null);
// Initialise data stream
this.dataStream = new byte[1024];
// Begin listening for broadcasts
clientSocket.BeginReceiveFrom(this.dataStream, 0, this.dataStream.Length, SocketFlags.None, ref epServer, new AsyncCallback(this.ReceiveData), null);
}
catch (Exception ex)
{
MessageBox.Show("Connection Error: " + ex.Message, "UDP Client", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
In the above code, the first thing we are doing is creating a Packet object and setting the data identifier to LogIn. When this packet is sent it will let the server know that a client wants to join the chat room. Next we are initialising the server and socket details and then the Packet is converted into a byte array and sent to the server. Finally the client starts listening for any broadcasts from the server and when it receives something the received data is processed with the below code:
private void ReceiveData(IAsyncResult ar)
{
try
{
// Receive all data
this.clientSocket.EndReceive(ar);
// Initialise a packet object to store the received data
Packet receivedData = new Packet(this.dataStream);
// Update display through a delegate
if (receivedData.ChatMessage != null)
this.Invoke(this.displayMessageDelegate, new object[] { receivedData.ChatMessage });
// Reset data stream
this.dataStream = new byte[1024];
// Continue listening for broadcasts
clientSocket.BeginReceiveFrom(this.dataStream, 0, this.dataStream.Length, SocketFlags.None, ref epServer, new AsyncCallback(this.ReceiveData), null);
}
catch (ObjectDisposedException)
{}
catch (Exception ex)
{
MessageBox.Show("Receive Data: " + ex.Message, "UDP Client", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
The above code is very simple. Since the client can only receive a Message from the server there is no need to process the data identifier which is at the beginning of the packet. Obviously, if you want your code to be robust and capable of handling any type of exception, you should check the data identifier… just in case.
All the code in this article can be made more robust. For example, there is no check to validate the IP address entered by the user in the client UI. There are no limits to the lengths of the input fields in the UI. There is no verification that the whole packet has in fact arrived in tact and uncorrupted. I think you get the picture… there is never a limit to the amount of checks you can perform and every good developer adds at least some of these checks to make the application more robust.
Conclusion
As you can see creating a client-server chat application using UDP is not that difficult. Obviously, there are many improvements you could make to this application. For example:
- assign a different colour to different users so as to easily identify them apart,
- allow sending of files (this would require a change to the custom data packet, and it would be better to use TCP instead of UDP for sending files,
- display a list of all connected users on every client UI,
- convert the server into a Windows Service to avoid starting it up manually,
- add support for emotions,
- implement a system to differentiate between users with the same name,
- etc.
I really hope you enjoyed this article. Please leave your comments below and don’t forget to download the whole code listing from below – it requires Microsoft Visual Studio 2008.
Also, if you haven’t already subscribed to my rss feed, please do so – Grab RSS Feed. And if you like you can also follow me on Twitter.
Dave
Download Chat Client source – 15.0 KB
Download Chat Server source – 14.8 KB
My name is David Azzopardi and I'm a software developer by profession. I have been working in the software industry for around eight years now and I have learned a few things through my experiences.
{ 16 comments… read them below or add one }
Hey thanks a lot…
It was helpfull:-)
Thanks for your comment. Glad you found it useful.
Dear Dave,
First of all, your program is perfect. The code is simple and easily understood.
I tried using my local IP; mean in my LAN, and I tried the program…It worked.
)… I tried using it .. that didnt work …
How about the world wide IP address? (I dont know if that is what they call it, but you know what I mean
Is your program intended to work in this case? or there is another way of doing it??
Thanks a lot
Hi Omar,
I’m glad you found the code easy to follow and understand.
The program should work over the Internet, but it must be behind a public fixed IP address. However, I have not tested this, but in theory it should work.
Dave
Thanks Dave …
… It takes a variable IP (which worked in the application) , so maybe it takes the place of the public IP
After reading your reply, I think the problem is i am using a USB modem
Therefore I am wondering if there is a function we can use to find out the IP my computer is currently utilizing to connect to the world over the internet
As far as I know there is no method to get the external IP address, especially if you are behind a router. You would have to rely on external services to give you your external IP. Many people choose to parse the html content returned from a site like http://www.whatismyip.com and get the IP from there, but personally I don’t really like that technique. Having said that I don’t know of a better way. Let us know if you find a way
You are right about the router issue … but I have another question..
can we use this program to send an image? …
I can see that before you send a packet, you convert everything using ‘BitConverter’ … If something similar can be used to send images, it would be great
You can send whatever you want over sockets – it’s binary data. To send an image, or any other file for that matter, you would do something like this:
To send the file:
// Create stream to load fileFileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
// Go to beginning of file
fs.Position = 0;
// Setup temporary buffer
byte[] tmpBuf = new byte[1024 * 1024];
while (fs.Position < fs.Length)
{
// Loop until we reach the end of file
int len = fs.Read(tmpBuf, 0, tmpBuf.Length);
// Write file to stream
dataStream.Write(tmpBuf, 0, len);
}
// Clean up
fs.Close();
To receive the file:
fileStream = new FileStream(file, FileMode.Append);readLenth = 0;
while ((readLenth < dataSize) && !exitLoop)
{
// Read data from socket
bytesReceived = socket.Receive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None);
// Exit loop if nothing was received
if (bytesReceived == 0)
{
exitLoop = true;
break;
}
readLenth += bytesReceived;
// Write received data to filestream
fileStream.Write(dataBuffer, 0, bytesReceived);
}
// Close filestream
socketData.FileStream.Close();
Hope that helps
Thanks again Dave … I will try this method later, but there is something more important I would like to ask about …
I have noticed that an error occurs on sending a large array of bytes … I mean a VERY large array … something that reaches multiple kilobytes … I dont what exactly limits the buffer size …
So, is there a method to send this large array by adjusting the original chat program code instead of the one you sent last time? (I was able to adjust the original code, but I am still limited by the allowed buffer size) …
Sorry for my continuous questions
Excellent work mate, exactly what I was looking for. Although, I know nothing about udp packets.
Would you mind giving me an insight on how to send a list of all the users currently connected to the clients? I tried but failed.
Hi Jayden. Thanks for your comments.
Why did you fail – what have you tried so far?
Hi Dave, thanks for your reply mate.
I failed at trying to add a new section to the packet, which sends the names to the client :\
Yo… Thanks you so much …because of you, I can refer your program and modify into what I need.
If possible, can I discuss with you for program? via mail?
Hey, I’m trying to get this to work as a WPF app, got the chat server up and running as a WPF app, now when I try to convert the client to WPF and run it, it connects to the server and the server receives the connection from the client, but I get an error that Receive Data:Vallue cannot be null. Parameter name method.
I don’t understand the error, I mean it’s the same code as on your windows forms application, why is this exception in the ReceiveData method being thrown?
Any clue would be awsome…
I am new in C# and I have some diffucults.
I want to send and receive image, but I don’t know how to use the code of image receive ,if you can Dave please write here the class ,where you use image receive method.
Thanks Dave…
{ 1 trackback }