TCP-сервер на сокетах

Последнее обновление: 05.11.2022

Класс Socket применяется не только для создания tcp-клиента, но для определения tcp-сервера. Общая схема работы серверного сокета TCP будет следующей:

Сервер на сокетах TCP в C# и .NET

Привязка к конечной точке. Метод Bind

Вначале серверный сокет с помощью метода Bind связывается с локальной точкой. В качестве параметра этот метод принимает локальную точку EndPoint, на которой сокет будет принимать подключения от клиентов:

public void Bind (EndPoint localEP);

Если не имеет значения, на каком именно локальном адресе сервер будет запущен, то можно в качестве адреса использовать значение IPAddress.Any. Тогда серверу будет назначен наиболее подходящий сетевой адрес (при наличии нескольких сетевых интерфейсов). Кроме того, если номер порта не имеет значения, то в качестве порта можно указать число 0. Тогда серверу будет предоставлен один из доступных портов. При использовании такого подхода точный адрес и порт затем можно будет получить через свойство LocalEndpoint.

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

IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888);
using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ipPoint);   // связываем с локальной точкой ipPoint

// получаем конечную точку, с которой связан сокет
Console.WriteLine(socket.LocalEndPoint); // 0.0.0.0:8888

В этом примере сокет будет прослушивать подключения по 8888 порту на любых локальных адресах. То есть клиент должен будет подключаться к локальному адресу, например, к 127.0.0.1, и порту 8888.

Прослушивание подключений. Метод Listen

Для запуска прослушивания подключений на выбранной локальной конечной точке применяется метод Listen:

public void Listen ();
public void Listen (int backlog);

При обращении к серверу входящие подключения помещаются в очередь для последующей обработки. По умолчанию эта очередь допускает 2147483647 подключений. Вторая версия метода Listen через параметр позволяет переопределить длину очереди.

stem.Net;
using System.Net.Sockets;

IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888);
using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ipPoint);   // связываем с локальной точкой ipPoint
socket.Listen(1000);    // запускаем прослушивание
                        // количество входящих подключений, которые можно поместить в очередь, равно 1000

Подключение клиента

После начала прослушивания сокет готов принимать подключения. Для приема подключений применяются методы Accept()/AcceptAsync(). Эти методы имеют ряд перегруженных версий. Отмечу саму простую из них:

public Task<Socket> AcceptAsync ();

Все версии методов Accept()/AcceptAsync() в качестве результа возвращают объект Socket, который инкапсулирует входящее подключение, то есть по сути представляет подключенного клиента.

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

IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888);
using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ipPoint);
socket.Listen();    
Console.WriteLine("Сервер запущен. Ожидание подключений...");
// получаем входящее подключение
using Socket client = await socket.AcceptAsync();
// получаем адрес клиента
Console.WriteLine($"Адрес подключенного клиента: {client.RemoteEndPoint}");

Через свойства Socket можно получить информацию о подключении клиента, в частности, свойство RemoteEndPoint позволяет получить адрес подключенного клиента.

Для такого просто сервера для теста определим клиент. Возьмем новый проект консольного приложения на C# и определим в нем следующий код:

using System.Net.Sockets;

using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
    await socket.ConnectAsync("127.0.0.1", 8888);
    Console.WriteLine($"Подключение к {socket.RemoteEndPoint} установлено");
}
catch (SocketException)
{
    Console.WriteLine($"Не удалось установить подключение с {socket.RemoteEndPoint}");
}

Здесь в метод ConnectAsync передаем данные конечной точки сервера и при успешном подключении выводим сообщение.

Запустим сервер, а затем запустим клиент. В итоге после подключения клиента к серверу в консоли сервера мы увидим что-то наподобие:

Сервер запущен. Ожидание подключений...
Адрес подключенного клиента: 127.0.0.1:52767

В данном случае мы видим, что в моем случае для подключения к серверу сокет-клиент использует адрес 127.0.0.1:52767. А в консоли клиента отобразится сообщение об успешном подключении:

Подключение к 127.0.0.1:8888 установлено
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850