C# > Networking > HTTP and Sockets > TcpClient and TcpListener

Simple TCP Server and Client with TcpListener and TcpClient

This example demonstrates a basic TCP server and client application using TcpListener and TcpClient in C#. The server listens for incoming connections, and the client connects to the server, sends a message, and receives a response.

Concepts Behind the Snippet

TcpListener is used on the server-side to listen for incoming TCP connections on a specified port. TcpClient is used on both the client and server to establish a TCP connection. The NetworkStream is then used to send and receive data over the established connection. This snippet uses synchronous operations for simplicity; real-world applications often employ asynchronous methods for better performance.

TCP Server Code

This code creates a TcpListener that listens on a specific port (13000 in this example). It accepts incoming connections using AcceptTcpClient(), reads data from the client using a NetworkStream, converts the received data to uppercase, and sends it back to the client. Error handling is included to catch potential SocketException errors, and the server stops listening when finished.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class TcpServer
{
    public static void Main(string[] args)
    {
        TcpListener server = null;
        try
        {
            // Set the TcpListener on port 13000.
            Int32 port = 13000;
            IPAddress localAddr = IPAddress.Loopback; // Or use IPAddress.Any to listen on all interfaces

            // TcpListener server = new TcpListener(port);
            server = new TcpListener(localAddr, port);

            // Start listening for client requests.
            server.Start();

            // Buffer for reading data
            Byte[] bytes = new Byte[256];
            String data = null;

            // Enter the listening loop.
            while (true)
            {
                Console.Write("Waiting for a connection... ");

                // Perform a blocking call to accept incoming connection.
                TcpClient client = server.AcceptTcpClient();
                Console.WriteLine("Connected!");

                data = null;

                // Get a stream object for reading and writing
                NetworkStream stream = client.GetStream();

                int i;

                // Loop to receive all the data sent by the client.
                while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    // Translate data bytes to a ASCII string.
                    data = Encoding.ASCII.GetString(bytes, 0, i);
                    Console.WriteLine("Received: {0}", data);

                    // Process the data sent by the client.
                    data = data.ToUpper();

                    byte[] msg = Encoding.ASCII.GetBytes(data);

                    // Send back a response.
                    stream.Write(msg, 0, msg.Length);
                    Console.WriteLine("Sent: {0}", data);
                }

                // Shutdown and end connection
                client.Close();
            }
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e);
        }
        finally
        {
            // Stop listening for new clients.
            server.Stop();
        }


        Console.WriteLine("\nHit enter to continue...");
        Console.Read();
    }
}

TCP Client Code

This code creates a TcpClient that connects to the TCP server at a specified address and port (127.0.0.1:13000 in this example). It sends a message to the server using a NetworkStream, receives a response, and displays both the sent message and the received response. Exception handling is included for potential ArgumentNullException and SocketException errors. Finally, the client closes the stream and the connection.

using System;
using System.Net.Sockets;
using System.Text;

public class TcpClientExample
{
    public static void Main(string[] args)
    {
        try
        {
            // Create a TcpClient.
            // Note, for this client to work you need to have a TcpServer 
            // connected to the same address as specified.
            TcpClient client = new TcpClient("127.0.0.1", 13000);

            // Translate the passed message into ASCII and store it as a Byte array.
            Byte[] data = Encoding.ASCII.GetBytes("Hello from client!");

            // Get a client stream for reading and writing.
            NetworkStream stream = client.GetStream();

            // Send the message to the connected TcpServer. 
            stream.Write(data, 0, data.Length);

            Console.WriteLine("Sent: {0}", "Hello from client!");

            // Receive the TcpServer.data.

            // Buffer to store the response bytes.
            data = new Byte[256];

            // String to store the response ASCII representation.
            String responseData = String.Empty;

            // Read the first batch of the TcpServer response bytes.
            Int32 bytes = stream.Read(data, 0, data.Length);
            responseData = Encoding.ASCII.GetString(data, 0, bytes);
            Console.WriteLine("Received: {0}", responseData);

            // Close everything.
            stream.Close();
            client.Close();
        }
        catch (ArgumentNullException e)
        {
            Console.WriteLine("ArgumentNullException: {0}", e);
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e);
        }

        Console.WriteLine("\n Press Enter to continue...");
        Console.Read();
    }
}

Real-Life Use Case

This type of TCP client/server setup can be used in various applications, such as: * **Chat Applications:** Real-time communication between users. * **Game Servers:** Handling player connections and data exchange in online games. * **Data Streaming:** Sending sensor data or other information from devices to a central server. * **Remote Control:** Controlling devices or software on a remote computer.

Best Practices

When working with TCP connections, it's important to consider these best practices: * **Asynchronous Operations:** Use asynchronous methods (e.g., AcceptTcpClientAsync, ReadAsync, WriteAsync) to prevent blocking the main thread and improve responsiveness, especially in server applications that handle multiple clients. * **Error Handling:** Implement robust error handling to catch exceptions like SocketException and handle them gracefully. Log errors for debugging and consider implementing retry mechanisms. * **Resource Management:** Always close streams and clients properly using Dispose() or using statements to release resources. * **Security:** If you are transmitting sensitive data, use encryption (e.g., SSL/TLS) to protect the communication. * **Keep-Alive:** Consider implementing TCP keep-alive messages to detect and handle broken connections. * **Connection Pooling:** If your application frequently creates and closes TCP connections, consider using connection pooling to improve performance.

Interview Tip

Be prepared to discuss the difference between TCP and UDP. TCP provides reliable, ordered delivery of data, while UDP is a connectionless protocol that does not guarantee delivery or order. TCP is suitable for applications that require reliable data transfer, while UDP is often used for streaming or gaming where some data loss is acceptable.

When to Use Them

Use TcpClient and TcpListener when you need to establish a reliable, connection-oriented communication channel between two applications. They are ideal for applications that require guaranteed delivery of data and where the order of the data is important.

Memory Footprint

The memory footprint of TcpClient and TcpListener depends on the amount of data being transmitted and buffered. Creating a large number of connections or buffering large amounts of data can increase memory usage. Use asynchronous operations and streaming to minimize memory consumption.

Alternatives

Alternatives to TcpClient and TcpListener include: * **UDP (UdpClient):** For connectionless communication where reliability is not critical. * **HTTP (HttpClient, HttpListener):** For web-based communication using the HTTP protocol. * **gRPC:** A modern, high-performance RPC framework. * **SignalR:** For real-time web applications. * **Named Pipes:** For inter-process communication on the same machine.

Pros

* Reliable, ordered data delivery. * Established connection for consistent communication. * Widely supported and well-understood protocol.

Cons

* Overhead of connection establishment and maintenance. * Can be slower than UDP due to error checking and retransmission. * More complex to implement than UDP.

FAQ

  • What's the difference between TcpClient and TcpListener?

    TcpListener is used on the server side to listen for incoming connection requests on a specified port. TcpClient is used on both the client and server side to establish a TCP connection.
  • How do I handle multiple clients with TcpListener?

    Use asynchronous methods (e.g., AcceptTcpClientAsync) and create a new thread or task to handle each client connection. This prevents blocking the main thread and allows the server to handle multiple clients concurrently.
  • How do I ensure data is transmitted securely over TCP?

    Use SSL/TLS encryption by wrapping the NetworkStream with a SslStream. This will encrypt the data being transmitted, protecting it from eavesdropping.