Simple Threaded TCP Server in C#
By FoxLearn 1/16/2025 3:36:00 AM 60
Building a Threaded TCP Server in C#
Our goal today is to create a TCP server that accepts client connections, sends and receives data, and spawns a separate thread for each client. While in theory, the server can accept as many connections as needed, the practical limitation is the number of threads the system can handle before performance starts to degrade.
Setting Up the Server
We’ll begin by setting up a basic server class. This class will use TcpListener
to handle the socket communication and a separate Thread
to listen for incoming client connections.
using System; using System.Text; using System.Net.Sockets; using System.Threading; using System.Net; namespace TCPServerTutorial { class Server { private TcpListener tcpListener; private Thread listenThread; public Server() { // Initializes the TcpListener to listen on all IP addresses, on port 3000 this.tcpListener = new TcpListener(IPAddress.Any, 3000); // Creates a new thread to handle client connections this.listenThread = new Thread(new ThreadStart(ListenForClients)); this.listenThread.Start(); } } }
In this setup:
TcpListener
is used to listen for incoming client connections on port 3000.- A separate thread,
listenThread
, is started to manage the client connections.
Listening for Clients
The ListenForClients
method will continuously listen for incoming client connections. When a connection is established, the server spawns a new thread to handle communication with the client.
private void ListenForClients() { // Start listening for incoming client connections this.tcpListener.Start(); while (true) { // Blocks until a client connects TcpClient client = this.tcpListener.AcceptTcpClient(); // Create a thread to handle communication with the connected client Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm)); clientThread.Start(client); } }
In this example:
tcpListener.Start()
begins listening for client connections.AcceptTcpClient()
blocks the main thread until a client connects.- Once a connection is made, the server creates a new thread (
clientThread
) to handle the interaction with the client. TheHandleClientComm
method will process this interaction.
Handling Client Communication
The HandleClientComm
method is responsible for reading data from the connected client. It runs in a loop, continuously receiving messages until the client disconnects or an error occurs.
private void HandleClientComm(object client) { TcpClient tcpClient = (TcpClient)client; NetworkStream clientStream = tcpClient.GetStream(); byte[] message = new byte[4096]; int bytesRead; while (true) { bytesRead = 0; try { // Blocks until a client sends data bytesRead = clientStream.Read(message, 0, 4096); } catch { // If an error occurs, break the loop break; } if (bytesRead == 0) { // If no data is read, the client has disconnected break; } // Successfully received data; process it ASCIIEncoding encoder = new ASCIIEncoding(); System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead)); } // Clean up after client disconnects tcpClient.Close(); }
In this example:
- The method reads data from the
NetworkStream
, which represents the stream of bytes sent by the client. - The loop continues as long as data is being received. If the client disconnects, the loop breaks.
- If data is successfully received, it’s converted to a string and printed to the debug console.
Sending Data to the Client
Once we’ve handled reading data from the client, let’s see how to send data back to the client.
NetworkStream clientStream = tcpClient.GetStream(); ASCIIEncoding encoder = new ASCIIEncoding(); byte[] buffer = encoder.GetBytes("Hello Client!"); clientStream.Write(buffer, 0, buffer.Length); clientStream.Flush();
In this example:
- We get the
NetworkStream
from theTcpClient
object. - The data (in this case, the string “Hello Client!”) is converted to a byte array using
ASCIIEncoding
. - The
Write
method sends the byte array to the client, andFlush
ensures the data is sent immediately.
Creating a Simple TCP Client
Though this tutorial focuses on the server, let's briefly look at how you can create a simple client that connects to the server and sends data.
TcpClient client = new TcpClient(); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000); client.Connect(serverEndPoint); NetworkStream clientStream = client.GetStream(); ASCIIEncoding encoder = new ASCIIEncoding(); byte[] buffer = encoder.GetBytes("Hello Server!"); clientStream.Write(buffer, 0, buffer.Length); clientStream.Flush();
You've built a basic threaded TCP server that accepts client connections, handles communication in separate threads, and sends data back to clients.
While the mechanics of setting up a threaded server are straightforward, a real-world application will need a protocol for structured communication between clients and the server.
- How to fix 'Failure sending mail' in C#
- How to Parse a Comma-Separated String from App.config in C#
- How to convert a dictionary to a list in C#
- How to retrieve the Executable Path in C#
- How to validate an IP address in C#
- How to retrieve the Downloads Directory Path in C#
- C# Tutorial
- Dictionary with multiple values per key in C#