Building a Simple Socket Listener in .NET Core

To listen to socket events in .NET Core, we can use the Socket class provided by the System.Net.Sockets namespace. Here is a step-by-step guide on how to set up a socket listener and handle incoming data.

Step 1. Set Up the Socket Listener.

First, you need to create a Socket instance and bind it to an endpoint. You can then start listening for incoming connections.

Step 2. Accept Connections and Receive Data.

When a client connects, you can accept the connection and then start receiving data from the connected socket.

Step 3. Handle the Received Data.

Here’s a complete example demonstrating how to listen for socket events, accept a connection, and read data from the socket in .NET Core.

Example

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

class Program
{
    private static async Task StartListener()
    {
        // Define the local endpoint for the socket
        IPAddress ipAddress = IPAddress.Any;
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);

        // Create a TCP/IP socket
        Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

        try
        {
            // Bind the socket to the local endpoint and listen for incoming connections
            listener.Bind(localEndPoint);
            listener.Listen(10);

            Console.WriteLine("Waiting for a connection...");

            while (true)
            {
                // Start an asynchronous socket to listen for connections
                Socket handler = await listener.AcceptAsync();

                // Create a task to handle the connection
                Task.Run(() => HandleConnection(handler));
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static async Task HandleConnection(Socket handler)
    {
        // Buffer for incoming data
        byte[] buffer = new byte[1024];
        string data = null;

        try
        {
            // An incoming connection needs to be processed
            while (true)
            {
                int bytesRec = await handler.ReceiveAsync(buffer, SocketFlags.None);
                if (bytesRec <= 0)
                {
                    break;
                }

                // Convert the byte array to a string
                data += Encoding.ASCII.GetString(buffer, 0, bytesRec);

                // Check for end-of-file tag. If it is not there, read more data
                if (data.IndexOf("<EOF>") > -1)
                {
                    break;
                }
            }

            // Show the data on the console
            Console.WriteLine("Text received : {0}", data);

            // Echo the data back to the client
            byte[] msg = Encoding.ASCII.GetBytes(data);
            await handler.SendAsync(msg, SocketFlags.None);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        finally
        {
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();
        }
    }

    public static void Main(string[] args)
    {
        // Start the socket listener in a background task
        Task listenerTask = StartListener();

        Console.WriteLine("Press ENTER to exit...");
        Console.ReadLine();
    }
}

Explanation

  1. Socket Setup: We create a Socket instance and bind it to an IPEndPoint that listens on all available network interfaces (IPAddress.Any) and port 11000.
  2. Listening for Connections: The listener.Listen(10) call configures the socket to listen for incoming connections. The AcceptAsync method is used to asynchronously accept incoming connections.
  3. Handling Connections: Each connection is handled in a separate task. The HandleConnection method reads data asynchronously from the connected socket using ReceiveAsync.
  4. Data Processing: The received data is accumulated in a string until an end-of-file tag ("<EOF>") is detected. The data is then echoed back to the client.
  5. Graceful Shutdown: Once the data is received and sent back, the connection is gracefully closed.

Running the Example

To run this example, ensure you have .NET Core installed. Save the code to a file, for example, Program. cs, and then run the following commands in your terminal:

dotnet new console -n SocketListener
cd SocketListener
mv ../Program.cs .
dotnet run

This will start the socket listener. You can test it by connecting to it with a TCP client, such as telnet or a custom client application.