Microsoft Docs

TCP Client/Server with System.Net.Sockets

This documentation provides an overview and examples of implementing TCP client and server applications using the System.Net.Sockets namespace in .NET.

Overview

TCP (Transmission Control Protocol) provides a reliable, ordered, and error-checked delivery of a stream of bytes between applications running on hosts communicating over an IP network. The System.Net.Sockets namespace offers classes that abstract the underlying socket functionality, making it easier to develop network applications.

Key Classes

Implementing a TCP Server

A TCP server typically involves the following steps:

  1. Create a TcpListener to listen on a specific IP address and port.
  2. Start the listener to begin accepting connections.
  3. In a loop, call AcceptTcpClient() to wait for and accept an incoming client connection.
  4. Once a client is accepted, obtain the NetworkStream from the TcpClient to send and receive data.
  5. Process the data received from the client.
  6. Send a response back to the client.
  7. Close the client connection and the stream when done.

Example Server Code (Conceptual C#)


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

public class SimpleTcpServer
{
    public static void StartListening()
    {
        int port = 13000;
        IPAddress localAddr = IPAddress.Parse("127.0.0.1");
        TcpListener server = null;

        try
        {
            server = new TcpListener(localAddr, port);
            server.Start();

            Console.WriteLine("Server started. Listening on port " + port);

            while (true)
            {
                Console.WriteLine("Waiting for a connection...");
                TcpClient client = server.AcceptTcpClient();
                Console.WriteLine("Client connected!");

                // Handle client connection in a separate thread
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            }
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: " + e.ToString());
        }
        finally
        {
            server.Stop();
        }
    }

    public static void HandleClientComm(object clientObj)
    {
        TcpClient tcpClient = (TcpClient)clientObj;
        string data = null;

        try
        {
            NetworkStream stream = tcpClient.GetStream();

            byte[] bytes = new byte[256];
            int i;

            while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
            {
                data = Encoding.ASCII.GetString(bytes, 0, i);
                Console.WriteLine($"Received: {data}");

                byte[] msg = Encoding.ASCII.GetBytes(data.ToUpper());
                stream.Write(msg, 0, msg.Length);
                Console.WriteLine($"Sent: {data.ToUpper()}");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine($"Error handling client: {e.Message}");
        }
        finally
        {
            tcpClient.Close();
            Console.WriteLine("Client disconnected.");
        }
    }

    //public static void Main(string[] args)
    //{
    //    StartListening();
    //}
}
            

Implementing a TCP Client

A TCP client typically involves these steps:

  1. Create a TcpClient instance.
  2. Use the Connect() method to establish a connection to the server's IP address and port.
  3. Obtain the NetworkStream from the connected TcpClient.
  4. Send data to the server using the stream.
  5. Receive data from the server.
  6. Close the connection when communication is complete.

Example Client Code (Conceptual C#)


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

public class SimpleTcpClient
{
    public static void Connect(String server, String message)
    {
        try
        {
            Int32 port = 13000;
            TcpClient client = new TcpClient();
            client.Connect(server, port);

            Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);

            NetworkStream stream = client.GetStream();

            stream.Write(data, 0, data.Length);
            Console.WriteLine($"Sent: {message}");

            data = new Byte[256];

            String responseData = String.Empty;

            int bytes = stream.Read(data, 0, data.Length);
            responseData = Encoding.ASCII.GetString(data, 0, bytes);
            Console.WriteLine($"Received: {responseData}");

            client.Close();
        }
        catch (ArgumentNullException e)
        {
            Console.WriteLine($"ArgumentNullException: {e}");
        }
        catch (SocketException e)
        {
            Console.WriteLine($"SocketException: {e}");
        }
    }

    //public static void Main(string[] args)
    //{
    //    Connect("127.0.0.1", "Hello from client!");
    //}
}
            

Important Considerations

  • Error Handling: Robust error handling is crucial for network applications. Implement try-catch blocks for potential SocketException, IOException, and other network-related errors.
  • Asynchronous Operations: For better performance and responsiveness, especially in UI applications, consider using asynchronous methods like ConnectAsync, AcceptTcpClientAsync, and ReadAsync/WriteAsync.
  • Data Serialization: For complex data structures, you'll need to implement serialization and deserialization mechanisms (e.g., JSON, XML, or custom binary formats).
  • Connection Management: Manage client connections efficiently. For servers handling many clients, consider using thread pools or asynchronous I/O to avoid blocking.
  • Security: For sensitive data, implement encryption and authentication mechanisms (e.g., TLS/SSL).

Further Reading