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
TcpListener
: Listens for incoming TCP connection requests.TcpClient
: Represents a TCP client that can connect to a remote host.NetworkStream
: Provides a stream for sending and receiving data over a network.
Implementing a TCP Server
A TCP server typically involves the following steps:
- Create a
TcpListener
to listen on a specific IP address and port. - Start the listener to begin accepting connections.
- In a loop, call
AcceptTcpClient()
to wait for and accept an incoming client connection. - Once a client is accepted, obtain the
NetworkStream
from theTcpClient
to send and receive data. - Process the data received from the client.
- Send a response back to the client.
- 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:
- Create a
TcpClient
instance. - Use the
Connect()
method to establish a connection to the server's IP address and port. - Obtain the
NetworkStream
from the connectedTcpClient
. - Send data to the server using the stream.
- Receive data from the server.
- 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
, andReadAsync
/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).