Geekpedia Programming Tutorials









C# Chat: Part 2 - Building the Chat Server

In this two part tutorial you will learn how to create a chat client that connects to a chat server and exchanges messages with all the other connected clients. This second part covers the development of the chat server.

On Saturday, October 20th 2007 at 04:41 PM
By Andrei Pociu (View Profile)
*****   (Rated 4.9 with 11 votes)
Contextual Ads
More C# Resources
Advertisement
» C# Chat: Part 1 - Building the Chat Client
» C# Chat: Part 2 - Building the Chat Server (currently reading)

Download this Visual Studio 2005 project Download the Chat Server Application project (Visual Studio 2005)

This is the second part of a tutorial that teaches you how to create a C# chat application. In Part 1 - Building the Chat Client we've looked at how to create the chat application that connects to a chat server, and here we now look at how to build the chat server.

The Chat Server

The Chat Server application is a tad more complex than the Chat Client application because it needs to hold information on all the connected clients, await for messages from each and send incoming messages to all. I commented all the code so hopefully you won't have any problems figuring it out without much commentary on the side from me.

Fire up a new instance of Visual Studio 2005 and in a new Windows Application project draw the following form:

Chat Server

The only controls we are interested in are the two TextBoxes (txtIp and txtLog) and the btnListen button. The IP address inside txtIp is the one where you want your chat server to be listening for incoming connections. You should use your local IP address, which if you're not in a network it could be 192.168.0.1, but it's best that you check using the ipconfig /all command in the MS-DOS Command Prompt window. The multi-line TextBox will hold information about connected clients and the messages that they are exchanging.

In the code view, start with the following using statements:

using System.Threading;

using System.Net;

using System.Net.Sockets;

using System.IO;


Move inside the class and declare a delagate which we will need in order to update the txtLog TextBox from another thread :

private delegate void UpdateStatusCallback(string strMessage);


Double-click the Start Listening button and you should arrive to it Click event. Have the event handler look like this:

private void btnListen_Click(object sender, EventArgs e)

{

    // Parse the server's IP address out of the TextBox

    IPAddress ipAddr = IPAddress.Parse(txtIp.Text);

    // Create a new instance of the ChatServer object

    ChatServer mainServer = new ChatServer(ipAddr);

    // Hook the StatusChanged event handler to mainServer_StatusChanged

    ChatServer.StatusChanged += new StatusChangedEventHandler(mainServer_StatusChanged);

    // Start listening for connections

    mainServer.StartListening();

    // Show that we started to listen for connections

    txtLog.AppendText("Monitoring for connections...\r\n");

}


A couple of objects are being instantiated, including a ChatServer object. We will write the ChatServer class very soon, and you will see that it handles all the incoming connections. In turn, it will make use of another class that we will write, called Connection.
The next thing we do is to set up an event handler for the StatusChanged event, which is a custom event that we're going to write very soon. It will inform us when a client has connected, a new message has been received, a client has disconnected, etc.
Finally the StartListening() method tells the ChatServer object to start listening for incoming connections.

Believe it or not, there are only a few more lines of code to go in this class. One of them is the event handler that we hooked earlier, and the other is the UpdateStatus() method that gets called when an update needs to be made to the form. It's needed because we use Invoke() and the delegate we created earlier to make a cross-thread call (since the ChatServer will be working in a different thread):

public void mainServer_StatusChanged(object sender, StatusChangedEventArgs e)

{

    // Call the method that updates the form

    this.Invoke(new UpdateStatusCallback(this.UpdateStatus), new object[] { e.EventMessage });

}

 

private void UpdateStatus(string strMessage)

{

    // Updates the log with the message

    txtLog.AppendText(strMessage + "\r\n");

}


And we're done. Done with the Form1 class, of course. You should now create another file (I called mine ChatServer.cs) and inside it make sure you have all these using statements:

using System;

using System.Collections.Generic;

using System.Text;

using System.Net;

using System.Net.Sockets;

using System.IO;

using System.Threading;

using System.Collections;


We'll need to use an event that notifies the form class when a new client has connected, disconnected, sent a message, etc. In order to create our own custom event, we need to first define its arguments. More exactly we want a string argument that tells us what type of event has occured (user has connected, user has disconnected, user x says y, etc..) If you're not familiar with events and delegates you might want to read the Delegates and Events in C# tutorial from a week ago. Here is the class that gets and sets the event arguments:

// Holds the arguments for the StatusChanged event

public class StatusChangedEventArgs : EventArgs

{

    // The argument we're interested in is a message describing the event

    private string EventMsg;

 

    // Property for retrieving and setting the event message

    public string EventMessage

    {

        get

        {

            return EventMsg;

        }

        set

        {

            EventMsg = value;

        }

    }

 

    // Constructor for setting the event message

    public StatusChangedEventArgs(string strEventMsg)

    {

        EventMsg = strEventMsg;

    }

}


Moving on, outside this class we declare the actual delegate for the event handler:

// This delegate is needed to specify the parameters we're passing with our event

public delegate void StatusChangedEventHandler(object sender, StatusChangedEventArgs e);


And now before we actually get to fire this event, we define the ChatServer class, in all its glory. Remember this is the class that we used back in Form1.cs:

class ChatServer

{

    // This hash table stores users and connections (browsable by user)

    public static Hashtable htUsers = new Hashtable(30); // 30 users at one time limit

    // This hash table stores connections and users (browsable by connection)

    public static Hashtable htConnections = new Hashtable(30); // 30 users at one time limit

    // Will store the IP address passed to it

    private IPAddress ipAddress;

    private TcpClient tcpClient;

    // The event and its argument will notify the form when a user has connected, disconnected, send message, etc.

    public static event StatusChangedEventHandler StatusChanged;

    private static StatusChangedEventArgs e;

 

    // The constructor sets the IP address to the one retrieved by the instantiating object

    public ChatServer(IPAddress address)

    {

        ipAddress = address;

    }

 

    // The thread that will hold the connection listener

    private Thread thrListener;

 

    // The TCP object that listens for connections

    private TcpListener tlsClient;

 

    // Will tell the while loop to keep monitoring for connections

    bool ServRunning = false;

 

    // Add the user to the hash tables

    public static void AddUser(TcpClient tcpUser, string strUsername)

    {

        // First add the username and associated connection to both hash tables

        ChatServer.htUsers.Add(strUsername, tcpUser);

        ChatServer.htConnections.Add(tcpUser, strUsername);

 

        // Tell of the new connection to all other users and to the server form

        SendAdminMessage(htConnections[tcpUser] + " has joined us");

    }

 

    // Remove the user from the hash tables

    public static void RemoveUser(TcpClient tcpUser)

    {

        // If the user is there

        if (htConnections[tcpUser] != null)

        {

            // First show the information and tell the other users about the disconnection

            SendAdminMessage(htConnections[tcpUser] + " has left us");

 

            // Remove the user from the hash table

            ChatServer.htUsers.Remove(ChatServer.htConnections[tcpUser]);

            ChatServer.htConnections.Remove(tcpUser);

        }

    }

 

    // This is called when we want to raise the StatusChanged event

    public static void OnStatusChanged(StatusChangedEventArgs e)

    {

        StatusChangedEventHandler statusHandler = StatusChanged;

        if (statusHandler != null)

        {

            // Invoke the delegate

            statusHandler(null, e);

        }

    }

 

    // Send administrative messages

    public static void SendAdminMessage(string Message)

    {

        StreamWriter swSenderSender;

 

        // First of all, show in our application who says what

        e = new StatusChangedEventArgs("Administrator: " + Message);

        OnStatusChanged(e);

 

        // Create an array of TCP clients, the size of the number of users we have

        TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];

        // Copy the TcpClient objects into the array

        ChatServer.htUsers.Values.CopyTo(tcpClients, 0);

        // Loop through the list of TCP clients

        for (int i = 0; i < tcpClients.Length; i++)

        {

            // Try sending a message to each

            try

            {

                // If the message is blank or the connection is null, break out

                if (Message.Trim() == "" || tcpClients[i] == null)

                {

                    continue;

                }

                // Send the message to the current user in the loop

                swSenderSender = new StreamWriter(tcpClients[i].GetStream());

                swSenderSender.WriteLine("Administrator: " + Message);

                swSenderSender.Flush();

                swSenderSender = null;

            }

            catch // If there was a problem, the user is not there anymore, remove him

            {

                RemoveUser(tcpClients[i]);

            }

        }

    }

 

    // Send messages from one user to all the others

    public static void SendMessage(string From, string Message)

    {

        StreamWriter swSenderSender;

 

        // First of all, show in our application who says what

        e = new StatusChangedEventArgs(From + " says: " + Message);

        OnStatusChanged(e);

 

        // Create an array of TCP clients, the size of the number of users we have

        TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];

        // Copy the TcpClient objects into the array

        ChatServer.htUsers.Values.CopyTo(tcpClients, 0);

        // Loop through the list of TCP clients

        for (int i = 0; i < tcpClients.Length; i++)

        {

            // Try sending a message to each

            try

            {

                // If the message is blank or the connection is null, break out

                if (Message.Trim() == "" || tcpClients[i] == null)

                {

                    continue;

                }

                // Send the message to the current user in the loop

                swSenderSender = new StreamWriter(tcpClients[i].GetStream());

                swSenderSender.WriteLine(From + " says: " + Message);

                swSenderSender.Flush();

                swSenderSender = null;

            }

            catch // If there was a problem, the user is not there anymore, remove him

            {

                RemoveUser(tcpClients[i]);

            }

        }

    }

 

    public void StartListening()

    {

 

        // Get the IP of the first network device, however this can prove unreliable on certain configurations

        IPAddress ipaLocal = ipAddress;

 

        // Create the TCP listener object using the IP of the server and the specified port

        tlsClient = new TcpListener(1986);

 

        // Start the TCP listener and listen for connections

        tlsClient.Start();

 

        // The while loop will check for true in this before checking for connections

        ServRunning = true;

 

        // Start the new tread that hosts the listener

        thrListener = new Thread(KeepListening);

        thrListener.Start();

    }

 

    private void KeepListening()

    {

        // While the server is running

        while (ServRunning == true)

        {

            // Accept a pending connection

            tcpClient = tlsClient.AcceptTcpClient();

            // Create a new instance of Connection

            Connection newConnection = new Connection(tcpClient);

        }

    }

}


Overwhelmed? It's really not that complicated if you take it line by line and read the comments. It starts by defining two hash tables. These two hash tables will hold the username and the TCP connection associated with it. We need two of them because at one point we'll want to retrieve the TCP connection by giving the username, and at some other point we'll want to retrieve the username by giving the TCP connection. The 30 defines how many users the chat server can hold at one given point, but you can easily go into hundreds if needed, without worrying about a performance decrease.

The AddUser() method is obvious - it adds a new user to the hash tables, and thus to our list of connected chat clients. The RemoveUser() method does the opposite. The OnStatusChanged will fire the StatusChanged event, which is right now handled inside Form1.cs. Thus, it's our way of updating the form with the latest message from inside this ChatServer object.

The SendAdminMessage sends an administrative message to all connected clients. You can see how it loops through the hash table and attempts to send them the message. If the message didn't get through, they probably disconnected and we then remove them. This is very similar to what the SendMessage() method does, only that this time it sends a message from a specific chat client to all the others.

The StartListening() method is the one we called inside Form1, and it's the fire starter, the instigator. It defines the first needed objects and starts a new thread that keeps listening for connections, and that is the KeepListening() method. And that's where our story continues, because if you look inside the KeepListening() method you will see we create a new object of type Connection. That's because each user connected to our server will have its own instance of Connection. If there are 10 users currently connected, there will be 10 instances of the Connection object. So let's look at the final class of our chat server:

// This class handels connections; there will be as many instances of it as there will be connected users

class Connection

{

    TcpClient tcpClient;

    // The thread that will send information to the client

    private Thread thrSender;

    private StreamReader srReceiver;

    private StreamWriter swSender;

    private string currUser;

    private string strResponse;

 

    // The constructor of the class takes in a TCP connection

    public Connection(TcpClient tcpCon)

    {

        tcpClient = tcpCon;

        // The thread that accepts the client and awaits messages

        thrSender = new Thread(AcceptClient);

        // The thread calls the AcceptClient() method

        thrSender.Start();

    }

 

    private void CloseConnection()

    {

        // Close the currently open objects

        tcpClient.Close();

        srReceiver.Close();

        swSender.Close();

    }

 

    // Occures when a new client is accepted

    private void AcceptClient()

    {

        srReceiver = new System.IO.StreamReader(tcpClient.GetStream());

        swSender = new System.IO.StreamWriter(tcpClient.GetStream());

 

        // Read the account information from the client

        currUser = srReceiver.ReadLine();

 

        // We got a response from the client

        if (currUser != "")

        {

            // Store the user name in the hash table

            if (ChatServer.htUsers.Contains(currUser) == true)

            {

                // 0 means not connected

                swSender.WriteLine("0|This username already exists.");

                swSender.Flush();

                CloseConnection();

                return;

            }

            else if (currUser == "Administrator")

            {

                // 0 means not connected

                swSender.WriteLine("0|This username is reserved.");

                swSender.Flush();

                CloseConnection();

                return;

            }

            else

            {

                // 1 means connected successfully

                swSender.WriteLine("1");

                swSender.Flush();

 

                // Add the user to the hash tables and start listening for messages from him

                ChatServer.AddUser(tcpClient, currUser);

            }

        }

        else

        {

            CloseConnection();

            return;

        }

 

        try

        {

            // Keep waiting for a message from the user

            while ((strResponse = srReceiver.ReadLine()) != "")

            {

                // If it's invalid, remove the user

                if (strResponse == null)

                {

                    ChatServer.RemoveUser(tcpClient);

                }

                else

                {

                    // Otherwise send the message to all the other users

                    ChatServer.SendMessage(currUser, strResponse);

                }

            }

        }

        catch

        {

            // If anything went wrong with this user, disconnect him

            ChatServer.RemoveUser(tcpClient);

        }

    }

}


It doesn't look too complicated, does it? There's the constructor that initializes the TcpClient object, then there's CloseConnection() which is called when we want to get rid of a currently connected client, and finally there's AcceptClient() which checks for the username validity and if all is fine, it adds the user to the hash tables. If anything goes bad, it removes the user.

I'll leave you chew on the code for a while now. It's pretty much as easy as it can get for a C# based chat/server application, but that also means it can use more error handling. Also if you have any suggestions to improve the code or to fix a bug, feel free to post a comment below.

Chat Server Application
Digg Digg It!     Del.icio.us Del.icio.us     Reddit Reddit     StumbleUpon StumbleIt     Newsvine Newsvine     Furl Furl     BlinkList BlinkList

Rate Rate this tutorial
Comment Current Comments
by }{ombr3 on Monday, October 22nd 2007 at 09:03 AM

Very helpful tutorial! Easy explained but a good variety of interesting c# classes...

I only changed the line

tlsClient = new TcpListener(1986);

to

tlsClient = new TcpListener(ipaLocal, 1986);

since this use of the method is deprecated;

I still haven\'t tested it yet, but i found some problems with exception handling, and the server .EXE still runs after exiting the application, but the rest goes well!

by }{ombr3 on Monday, October 22nd 2007 at 09:05 AM

oncy i've tried to integrate animations (icons, gifs, anis) into a chat application in c#... but i didn't find out how to solve this... has any one an idea? Thanks

by boris on Tuesday, October 23rd 2007 at 08:27 AM

hhhmmm.... something's seriously wrong with the code.
client crashes every time user tries to disconnect. i can't seem to solve this, but it has to do with the threading. also when tcpclient closes, connection stays open. i couldn't find the way to kill it.

server's thread is also runnig after the server windows closes (and stays active till system restart).

any thoughts?

p.s. nevertheless, i think this is one of the best c# sockets tutorials on net so far.

by Andrei Pociu on Tuesday, October 23rd 2007 at 10:35 AM

For fixing the server's thread - you should do the same thing that we did for the client in the OnApplicationExit event.

The problem I could reproduce, as the two of you mentioned, is the one where the client crashes when you close it. I'll take care of it and update the tutorial, it's nothing major.

By the way, the server application could be transformed into a service so that it runs in the background. The incoming messages could be written to a log file.

by john mackrugger on Wednesday, October 24th 2007 at 01:34 PM

i like this tutorial I have question where is the "e" declaration in

public static void SendAdminMessage(string Message)

{

StreamWriter swSenderSender;



// First of all, show in our application who says what

e = new StatusChangedEventArgs("Administrator: " + Message);

OnStatusChanged(e);

by Chryso on Wednesday, October 24th 2007 at 06:15 PM

I fixed the client error by changing the:
while (Connected)

{

// Show the messages in the log TextBox

this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });

}

code in private void ReceiveMessages() to:

while (Connected == true)

{
try
{
// Show the messages in the log TextBox
this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
}
catch{}
}

by boris on Friday, October 26th 2007 at 08:48 AM

Chryso, does your fix close network stream between client and server?

by Tylar on Saturday, October 27th 2007 at 12:51 AM

Excellent tutorial! It filled in a lot of the gaps that I had with some of the networking code required for a project such as this. I plan to address some of the bugs and maybe add a few features here and there to this code. If it ends up being a worth while adventure I will be sure to post my changes here. Keep up the great work!

by Peter on Wednesday, November 14th 2007 at 09:27 PM

Unfortunately, this does not convert well over to .Net 3.0. The only part I couldn\'t get to work was the \"this.Invoke\" part. Since, WPF does not use System.Windows.Forms at all. but otherwise, pretty helpful code. thanks.

by Martin on Monday, November 19th 2007 at 02:38 PM

I followed the first part of this tutorial series as well as this second part exactly, word for word. My code is nearly identical although some of my comments contained additional writing just for myself.

I had absolutely no success in getting it to work. At first, the Client would crash upon clicking the connect button. I followed some suggestions in the other comments, and prevented the client from crashing, but it still never connects. Upon debugging the server one time, VC# Express informed me of something being deprecated, but it went away and I have no idea what it was now.

I thought I was actually learning but apparently I'm not if it doesn't even work - and to my knowledge, the application failure isn't a result of anything I've done. *sigh*, and this tutorial was the best I've found for C#.

Oh well, best of luck to everyone else. Cheers.

by Andrei Pociu on Monday, November 19th 2007 at 04:48 PM

Martin,

Your problem is surely something that can be fixed, but you'll need to tell us where does it crash (the exception message, possibly the line number.)

by Martin on Thursday, November 22nd 2007 at 02:55 AM

Alright, now that I\'ve gained some more free time to look into this, I\'ve realized now that the client is still crashing, but rather than crashing on-click of the Connect button, it\'s crashing during the process of actually trying to make the connection.

VC# Exp is saying:

\"NullReferenceException was unhandled.
Object reference not set to an instance of an object.\"

It says the above in regards to the following line from the client\'s Form1.cs (which it highlighted):

if (ConResponse[0] == \'1\')

I checked the Part 1 of this tutorial series for that line & mine is exactly as the tutorial\'s. VC# suggests using the \"new\" keyword to create an object instance, but I\'m not necessarily sure I understand what that means... I come from a background of interpreted languages and so I wonder if I\'m just not fully comprehending how objects work in C#, although I thought I had at least \'some\' idea.

by amin on Sunday, November 25th 2007 at 04:30 AM

hello it is ok

by HondaCop on Monday, December 17th 2007 at 06:21 AM

Sorry for my ignorance, but what if I want to deply such an application? Do I need to run a windows box as my webserver, so I can have the server instance of this application running 24/7 and thus be able to serve as the chat server for anyone who connects on their end?

by Andrei Pociu on Monday, December 17th 2007 at 09:17 AM

HondaCop - yes, that is correct.

by HondaCop on Monday, December 31st 2007 at 02:09 PM

Thanks for the response, Andrei... I got this working and it\'s simply awesome. I will be doing some modifications to it, to suit my needs. I have 2 questions though...

1. How can I convert the ChatServer to run as a windows service?
2. Have you developed another version of this chat system? I am interested in perhaps being able to have 2 more features:
- Ability to send private messages
- Have a list of connected users

Thanks for any help on this, my friend, and THANKS for your contributions. They are greatly appreciated.

by Matjaz on Tuesday, January 1st 2008 at 12:51 PM

Great code! But how to terminate server process after server's window closes??? Server's process still exists ...

by HondaCop on Wednesday, January 2nd 2008 at 02:08 PM

Can someone please tell me how to make the Server send the list of connected users to the Client, once he connects?

Thanks in advanced.

by Soulice on Monday, January 7th 2008 at 03:00 PM

Liking this. I solved both client and server thingys and swapped the textbox for a richtext box to bold incoming messages and added a flatfile to store user prefs for ip and username. Neat app and great tut!

by HondaCop on Friday, January 11th 2008 at 09:33 AM

Soulice, do you mind sharing your custom code? I would love to be able to solve the crashing problem which occurs when a client is disconnected suddenly.

by sundar on Saturday, January 12th 2008 at 01:41 PM

hi, this is a tutorial with great explanations ans coding. Actually i want to try sending msg from a pc to another on network through the server( it shouldnt be visible to others). what will be the modification that i will have to do in this code.

Thanks ,

by The Midnighter on Friday, January 25th 2008 at 10:12 PM

I've fixed most of the errors... Except I still can't figure out how to close the frickin' client once the streams are open....

by Rudi on Saturday, January 26th 2008 at 05:12 AM

Excellent Tutorial!

Can someone help with closing the server application when the user closes the app? It seems as the thread to listen is still running but I cannot figure it out.

Thanks

by sundar on Saturday, February 2nd 2008 at 10:24 AM

hi Andrei,

When the client gets diconnected from Server, the Server crashes and the Debugging pointer points to this line in FORM1.CS :
public void mainServer_StatusChanged(object sender, StatusChangedEventArgs e)
{
// Call the method that updates the form
this.Invoke(new UpdateStatusCallback(this.UpdateStatus), new object[] { e.EventMessage });
}
Pl help me Dude !!!

by sundar on Friday, February 8th 2008 at 12:30 PM

hi andrei,

Why are we using 2 hash tables, but both stores the same information.
And how we can add "Themes" facility into our C# windows appln ?

help me ... pl

by sundar on Tuesday, February 12th 2008 at 10:32 AM

hi friends,

Why are we using 2 hash tables, but both of these uses the same data to store.

by viper on Saturday, February 16th 2008 at 09:34 AM

Hi Together

"server's thread is also runnig after the server windows closes (and stays active till system restart)."

Is there a somewhere a solution to this problem?

by on Monday, March 17th 2008 at 05:18 AM

this is a good example, however, in the first time, i can you it, but now when i run it, it display the error \\\"socketexception was unhandled, so can you help me to fix this problem. thank you so much for your code and for your help.

by Alexander Tutass on Monday, March 24th 2008 at 03:55 AM

The reason why the server throws an exception if it should be closen, it is because:
// Create the TCP listener object using the IP of the server and the specified port
tlsClient = new TcpListener(myIP, 1986);
in method public void StartListening()
keeps beeing in an inner thread and can only be stopped by force, as far as I know.

So I used a new method in the form-class:

private void ServerForm_FormClosing(object sender, FormClosingEventArgs e)
{
mainServer.RequestStop();
}


which trys to stop the TcpListener waiting by using this implementation in the server class:

public void RequestStop()
{
if (thrListener != null && thrListener.IsAlive) // thread is active
{
// set event \"Stop\"
tlsClient.Stop();
ServerIsActive = false;

while (thrListener.IsAlive)
{
Application.DoEvents();
}
}
}

So the only thing left is to catch the exception in KeepListening() by:

private void KeepListening()
{

// While the server is running
while (ServerIsActive)
{
try
{
// Accept a pending connection
tcpClient = tlsClient.AcceptTcpClient();

// Create a new instance of Connection
Connection newConnection = new Connection(tcpClient);
}
catch (SocketException e)
{
; // Do nothing
}
}
}

That one fixes it for me..

by Alex on Monday, March 24th 2008 at 03:59 AM

ups I changed some things already in my code so it may be hard to follow the code:

ServerIsActive is the bool ServRunning

I hope this was all.

by ademola yemi on Tuesday, March 25th 2008 at 09:19 AM

am yet to test this tutorial but geekpedia has been helpful. more power to your elbow!

by taffer on Thursday, March 27th 2008 at 11:03 AM

hey guys i included a listbox in the client apllication.i want to populate it with the users hashtable .so how can i do that.
how can i pass a hashtable to a client that is just usernames

by Slaugtherjoe on Wednesday, April 23rd 2008 at 06:04 AM

Great tutorial! One little thing:
You might change the order of:

if (htConnections[tcpUser] != null)
{
SendAdminMessage(htConnections[tcpUser] " has left us");

ChatServer.htUsers.Remove(ChatServer.htConnections[tcpUser]);

ChatServer.htConnections.Remove(tcpUser);
}

into:
ChatServer.htUsers.Remove(ChatServer.htConnections[tcpUser]);

ChatServer.htConnections.Remove(tcpUser);
SendAdminMessage(htConnections[tcpUser] " has left us");

since it produces an unwanted dead-loop in case the connection broke in an unpropper way (The Admin-Message tries to send the Message to a person that no longer exists, which causes in a new removal of the person...

by Slaughterjoe on Wednesday, April 23rd 2008 at 06:15 AM

... but you have to store the name of the leaving client first :) into a string first. ouch!

string uname = htConnections[tcpUser].ToString();
htUsers.Remove(htConnections[tcpUser]);
htConnections.Remove(tcpUser);
SendAdminMessage(uname " has left us");

by fox_11 on Saturday, May 3rd 2008 at 03:29 AM

I decided to make network small game in my one lesson.
So i need some help
How to know server's(listening) ipaddress from client


Comment Comment on this tutorial
Name: Email:
Message:
Comment Related Tutorials

C# Chat: Part 1 - Building the Chat Client

On Saturday, October 20th 2007 at 12:43 PM by Andrei Pociu in C#

Delegates and Events in C#

On Saturday, October 13th 2007 at 09:59 PM by Andrei Pociu in C#

File transfers through networks and the Internet

On Wednesday, May 3rd 2006 at 08:28 PM by Andrei Pociu in C#


Comment Related Source Code
There is no related source code.

Jobs C# Job Search
My skills include:
Enter a City:

Select a State:


Advanced Search >>
Latest Tech Bargains

Advertisement

Free Magazine Subscriptions

Today's Pictures

Today's Video

Other Resources

Latest Downloads

Latest Icons