Подумываете о запуске клиент-серверного взаимодействия на C#, но не дается весь этот сетевой жаргон? Сегодня мы разберемся с ним, прибегнув к простому TCP  —  протоколу управления передачей. Сделаем так, чтобы приложения C# «общались» по сети, как старые друзья.

Создадим простую TCP-настройку клиента и сервера. Это как телефонный разговор двух человек: один  —  сервер, им звонки прослушиваются, другой  —  клиент, им звонок совершается.

Итак, погрузимся в мир TCP-коммуникаций с кодом и техническими нюансами, чтобы в ближайший перерыв на кофе не ударить в грязь лицом перед коллегами.

В чем прикол с этим TCP?

TCP  —  это как почта интернета. Сообщение здесь гарантированно доставляется адресату в правильной последовательности и без пропусков. TCP надежен и подключение-центричен. Он оптимален, когда нужно, чтобы получалось ровно то, что отправляется.

Подготовим сервер и клиент

Создадим на C# простой сервер для прослушивания соединений и клиент, который подключается для отправки сообщений. Сервер  —  это как кофейня, а клиент  —  кофеинозависимый, который отчаянно нуждается в утренней дозе.

Создадим сервер

Начнем с сервера. Он прослушивает входящие соединения, обрабатывая каждое отдельно. Вот код:

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

public class SimpleServer
{
private TcpListener listener;
private List<TcpClient> clients = new List<TcpClient>(); // Отслеживаются подключенные клиенты

public void Start(int port)
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
Console.WriteLine("Server started, waiting for connections...");

Thread acceptThread = new Thread(AcceptClients);
acceptThread.Start();
}

private void AcceptClients()
{
while (true)
{
try
{
TcpClient client = listener.AcceptTcpClient();
clients.Add(client);
Console.WriteLine("Client connected.");

Thread clientThread = new Thread(() => HandleClient(client));
clientThread.Start();
}
catch (Exception ex)
{
Console.WriteLine("Error accepting client: " + ex.Message);
}
}
}

private void HandleClient(TcpClient client)
{
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
int bytesRead;

try
{
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + message);

// Сообщение возвращается клиенту
byte[] response = Encoding.UTF8.GetBytes("Echo: " + message);
stream.Write(response, 0, response.Length);
}
}
catch (Exception ex)
{
Console.WriteLine("Error communicating with client: " + ex.Message);
}
finally
{
stream.Close();
client.Close();
clients.Remove(client);
Console.WriteLine("Client disconnected.");
}
}
}

class Program
{
static void Main()
{
SimpleServer server = new SimpleServer();
server.Start(5000); // Выбирается порт, любой
}
}

Принцип работы

  • TcpListener  —  это «уши» сервера, ими прослушиваются входящие соединения.
  • У каждого клиентского соединения собственный поток  —  сервер не зависнет в ожидании клиента. Многозадачность во всей красе!
  • Сервером сообщения возвращаются клиенту. Схема простая, зато рабочая.

Теперь создадим клиента

На стороне клиента все чуть проще. Клиент подключается к серверу, отправляет сообщение, а затем с нетерпением ожидает ответа сервера:

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

public class SimpleClient
{
private TcpClient client;
private NetworkStream stream;

public void ConnectToServer(string ipAddress, int port)
{
client = new TcpClient(ipAddress, port);
stream = client.GetStream();
Console.WriteLine("Connected to the server.");

// Начинается считывание сообщений в фоновом режиме
ReadMessages();
}

private void ReadMessages()
{
byte[] buffer = new byte[1024];
int bytesRead;

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Server says: " + message);
}
}

public void SendMessage(string message)
{
if (stream != null && stream.CanWrite)
{
byte[] data = Encoding.UTF8.GetBytes(message);
stream.Write(data, 0, data.Length);
Console.WriteLine("Message sent: " + message);
}
}
}

class Program
{
static void Main()
{
SimpleClient client = new SimpleClient();
client.ConnectToServer("127.0.0.1", 5000); // Подключение к локальной машине

Console.WriteLine("Type a message to send:");
string message = Console.ReadLine();
client.SendMessage(message);
}
}

Вкратце о клиенте

  • Клиент подключается к серверу с помощью TcpClient, как при входе в личные сообщения на сервере.
  • Сообщения отправляются через NetworkStream, ответы считываются из того же потока.
  • Это как портативная рация: нажимаешь  —  говоришь, отпускаешь  —  слушаешь.

Заключение

Вот и все. Простой клиент-сервер TCP на C# готов. Награду за сложность не получит, но работу выполнит на отлично. Это основа для продвинутых сетевых приложений. Создаете чат, многопользовательскую игру или просто хотите взаимодействия двух программ, TCP  —  ваш надежный друг. Не забывайте делать потоки чистыми, корректно обрабатывать исключения и никогда не доверять данным, пока не проверили их. 

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Jean-Michel KEULEYAN: C# — TCP Communications: Building a Client-Server Chat

Предыдущая статья10 концепций разработчика Laravel
Следующая статьяАвтомасштабирование по запаздыванию Kafka с KEDA