TCP-сервер. Класс TcpListener

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

Класс TcpListener выполняет роль сервера. Он прослушивает входящие подключения по определенному порту. Стоит отметить, что класс TcpListener построен на основе класса сокета Socket, то есть фактически представляет обертку над классом Socket и позволяет упростить написание некоторых вещей, по сравнению с использованием чистых сокетов.

Создание TcpListener

Объект TcpListener характеризуется адресом и портом, на которых запущен сервер. Для инициализации объекта TcpListener применяется один из его конструкторов:

public TcpListener (System.Net.IPAddress localaddr, int port);
public TcpListener (System.Net.IPEndPoint localEP);

Первый конструктор задает адрес и порт прослушивания сервера:

IPAddress localAddr = IPAddress.Parse("127.0.0.1");
TcpListener server = new TcpListener(localAddr, 8888);

В данном случае TCP-сервер запущен по адресу "127.0.0.1" на порту 8888.

Второй конструктор принимает объект IPEndPoint

IPAddress localAddr = IPAddress.Parse("127.0.0.1");
IPEndPoint ipLocalEndPoint = new IPEndPoint(localAddr, 8888);
TcpListener server = new TcpListener(ipLocalEndPoint);

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

TcpListener server = new TcpListener(IPAddress.Any, 0);
Console.WriteLine(server.LocalEndpoint);

Прослушивание запросов

Для организации получения входящих запросов TcpListener применяет ряд методов. Основные из них:

  • AcceptSocket()/AcceptSocketAsync(): принимает ожидающий запрос на подключение. Возвращает объект Socket, который используется для связи с клиентом

  • AcceptTcpClient()/AcceptTcpClientAsync(): принимает ожидающий запрос на подключение. Возвращает объект TcpClient, который используется для связи с клиентом

  • Pending(): определяет, есть ли ожидающие запросы на подключение. Возвращает true, если имеются ожидающие подключения; в противном случае — false..

  • Start(): запускает сервер.

    Перегрущка метода Start(Int32) в качестве параметра принимает максимальную длину очереди ожидающих подключений.

  • Stop(): останавливает сервер.

Общий процесс работы TcpListener выглядит следующим образом:

  1. Для запуска сервера вызывается метод Start().

    TcpListener server = new TcpListener(IPAddress.Any, 8888);
    server.Start();
    

    Метод Start инициализирует используемый объект Socket, связывает его с локальной конечной точкой и начинает прослушивать входящие запросы. При получении входящего запроса он помещается в очередь. Если в очереди не окажется места для нового подключения, то будет сгенерировано исключение SocketException. По умолчанию максимальное количество, которое может содержать очередь ожидания, равно 2147483647.

  2. Когда к серверу обращается клиент, то мы можем использовать один из двух методов AcceptSocket)/AcceptSocketAsync() или AcceptTcpClient()/AcceptTcpClientAsync() для получения из очереди подключения в виде объекта Socket или TcpClient соответственно.

    TcpClient client = await server.AcceptTcpClientAsync();
    // или
    Socket socket = await server.AcceptSocketAsync();
    

    Полученные объекты TcpClient и Socket инициализируется IP-адресом и номером порта удаленного узла. Далее через методы этих классов можно взаимодействовать с подключенным клиентом: получать от него данные или, наоборот, отправлять ему.

  3. В конце по завершению работы сервера надо вызвать метод Stop(). При этом все оставшиеся в очереди подключения будут потеряны.

Подключение tcp-клиента к tcp-серверу

Определим следующий код сервера:

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

var tcpListener = new TcpListener(IPAddress.Any, 8888);
try
{
    tcpListener.Start();    // запускаем сервер
    Console.WriteLine("Сервер запущен. Ожидание подключений... ");

    while (true)
    {
        // получаем подключение в виде TcpClient
        using var tcpClient = await tcpListener.AcceptTcpClientAsync();
        Console.WriteLine($"Входящее подключение: {tcpClient.Client.RemoteEndPoint}");
    }
}
finally
{
    tcpListener.Stop(); // останавливаем сервер
}

После запуска сервера в бесконечном цикле прослушиваем входящие подключения и при получении выводим на консоль адрес подключения.

Для подключения к этому серверу определим в другом проекте следующий код клиента:

using System.Net.Sockets;

using TcpClient tcpClient = new TcpClient();
Console.WriteLine("Клиент запущен");
await tcpClient.ConnectAsync("127.0.0.1", 8888);

if (tcpClient.Connected)
    Console.WriteLine($"Подключение с {tcpClient.Client.RemoteEndPoint} установлено");
else
    Console.WriteLine("Не удалось подключиться");

Клиент подключается к выше определенному серверу. Поскольку сервер запущен на локальном компьютере и доступен по любому локальному адресу и порту 8888, то для подключения к нему используем локальный адрес "127.0.0.1" и порт 8888.

После успешного подключения просто выводим на консоль диагностическое сообщение.

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

Сервер запущен. Ожидание подключений...
Входящее подключение: 127.0.0.1:56469

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

Клиент запущен
Подключение с [::ffff:127.0.0.1]:8888 установлено

Здесь можно отметить, что клиент подключился по адресу "::ffff:127.0.0.1" - фактически это IPv6-версия IPv4-адреса 127.0.0.1.

Получение сокета

Аналогично мы можем получать входящее подключение в виде сокета:

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

var tcpListener = new TcpListener(IPAddress.Any, 8888);

try
{
    tcpListener.Start();    // запускаем сервер
    Console.WriteLine("Сервер запущен. Ожидание подключений... ");

    while (true)
    {
        // получаем подключение в виде Socket
        using var tcpSocket = await tcpListener.AcceptSocketAsync();
        Console.WriteLine($"Входящее подключение: {tcpSocket.RemoteEndPoint}");
    }
}
finally
{
    tcpListener.Stop();
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850