Класс Socket применяется не только для создания tcp-клиента, но для определения tcp-сервера. Общая схема работы серверного сокета TCP будет следующей:
Вначале серверный сокет с помощью метода 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:
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 установлено