Tcp Listener With .Net Core

Publish date: May 26, 2019
Tags: .net, .net core, tcp, c#

Creating a TCP Listener to listen on port 12345

To create a TCP Listener, that would listen on port ‘12345’ on your localhost, you just need to use a TcpListener class from System.Net.Sockets library, like so:

using System.Net.Sockets;
...
var listener = new TcpListener(IPAddress.Any, 12345);
listener.Start();

But in order to listen we will need to conjure up a while loop, in which we will accept the incoming connections. In this loop, we can accept each incoming connection and operate on it, by:

  1. Calling listener.AcceptTcpClient(), which will also return the client, which just connected.
  2. Getting the stream for that client.
  3. Creating StreamWriter and StreamReader instances, and passing them this stream.
  4. Writing to, and reading from the stream, using the instances from above.

Handling the disconnect of the client

If the client goes offline, one would think that calling listener.Connected, or stream.CanWrite would let us know that the listener is not connected anymore, or that the stream is not writable anymore, and we should proceed differently (stop communicating).

However this is not the case if the connection is not closed properly, to find out that the client has disconnected there is a way to use Poll() method and check if the reader will read in 0, which is more lines of code and it not always reliable, so to the best of my knowledge I chose to go with try/catch block and handling the IOException which is thrown when we cannot read/write from/to stream anymore. This definitely means that the client is now disconnected for some reason.

Final product

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace tcp
{
    class Program
    {

        static void Main(string[] args)
        {
            var listener = new TcpListener(IPAddress.Any, 12345);
            listener.Start();
            while (true)
            {
                System.Console.WriteLine("Waiting for client to connect...");
                var client = listener.AcceptTcpClient();
                System.Console.WriteLine("Client connected!");
                var clientStream = client.GetStream();

                StreamWriter sw = new StreamWriter(clientStream);
                StreamReader sr = new StreamReader(clientStream);
                System.Console.WriteLine($"Client is saying: { sr.ReadLine() }" );
                sw.Write($"Listener says hi! { Environment.NewLine }");
                sw.Flush();

                while (true)
                {
                    Thread.Sleep(2000);
                    try
                    {
                        sw.Write($"Listener keeps talking to the client. { Environment.NewLine }");
                        sw.Flush();
                    }
                    catch (IOException e)
                    {
                        client.Close();
                        System.Console.WriteLine($"Client disconnected: { e.InnerException.Message }");
                        break;
                    }
                }
            }
        }
    }
}

Usage

At this point open two terminals, in first one you should be able to simply do your

dotnet run

App will be waiting for connection now. “Sveto, but I don`t have a client to connect to this listener..“. No problem, bring up second terminal window and do:

echo 'hi!' | nc localhost 12345

This will initiate the connection between netcat utility and your server on the port you specified, as well as send the message ‘hi!’. You should now see outputs from both terminals (one with the listener running, one with the client connected). If you are still in the client terminal, hit CTR+C to cancel the client, and disconnect. You should now see that the listener is still running, saying that the previous client disconnected because of broken pipe, and is waiting for another connection.