TCP Chat - Server

I've seen many networking tutorials that start you with the client code.  I think it's better to start off with the server code first.  And there is quite a bit here.

The main two classes that are used here are TcpClient & TcpListener.   In a nutshell, we use TcpListener to listen for incoming connections, then once someone has connected, we spin up a new TcpClient to talk to that remote process.

Here is the code for the server:



When instancing the class TcpChatServer, the listener is created but doesn't start listening until we call Start() on it in the Run() method.  IPAddress.Any, means "let anyone from any network interface connect to me."

The Run() method is the main heart of the program.  Like said above, when we make the call to _listener.Start(), the TcpListener will start listening for new incoming TCP connections the port we fed it (6000 our case).  If there is a new pending connection (checked via the Pending() method), we break into a function see who the new client is.

_handleNewConnection() does what the name implies.  After the connection has been established we can grab it's TcpClient instance by calling AcceptTcpClient in the listener, the client should send a message stating either viewer or name:MY_NAME.

  • If we have a new Viewer, recognize that client as a viewer, and then send them a welcome message
  • If we have a new Messenger, verify that MY_NAME hasn't been taken yet
    • If so, enqueue a new message to tell the Viewers that a new friend has joined us
    • Else, close the connection
  • Anything else, say that we couldn't identify who they are, and then close the connection

Back in Run(), we check for disconnects, new messages, and then send queued ones in the rest of the loop.  There is also a call to Thread.Sleep(10), so that we save on CPU resources.

_checkForDisconnects()  are two foreach loops that go through all of the clients and use the _isDisconnected() method to test for the FIN/ACK packets that might have been sent.


The Connected property of TcpClient might seem like the right thing to use here instead of _isDisconnected(), but there's a problem with that.  Connected returns true only if the last IO operation was a success.  This means that the FIN/ACK might have been sent, but since there were no IO operations on our end, Connected will still return true.  Be careful of this.


_checkForNewMessages() is also a foreach check of all the Messengers.  We can use the Available property to see how big their message is (in bytes), and then read that from the client's NetworkStream.

_sendMessages() empties the _messageQueue by writing the the Viewer's streams.

There is also the function _cleanupClient().  It's a small helper that closes both the TcpClient's NetworkStream and itself.


If you are wondering why we need to manually close the stream ourselves, is because the stream is created from the underlying Socket object (which can be accessed via TcpClient's Client property).  This means you need to clean it up manually.  Read more about it here.

© – Made using & love.
Back to Top of Page
This site uses cookies.