Использование сокетов для отправки и получения данных по протоколу TCP

Перед использованием сокета для связи с удаленными устройствами необходимо инициализировать сокет, указав протокол и сведения о сетевом адресе. Конструктор класса Socket имеет параметры, которые определяют семейство адресов, тип сокета и тип протокола, которые сокет использует для подключения. При подключении сокета клиента к сокету сервера клиент будет использовать IPEndPoint объект для указания сетевого адреса сервера.

Создание конечной точки IP-адреса

При работе с System.Net.Socketsвы представляете конечную точку сети в IPEndPoint виде объекта . Создается IPEndPoint с соответствующим номером IPAddress порта. Прежде чем начать беседу с помощью Socket, вы создадите канал данных между приложением и удаленным назначением.

В качестве уникального идентификатора службы протокол TCP/IP использует сетевой адрес и номер порта службы. Сетевой адрес идентифицирует конкретное сетевое назначение; номер порта определяет конкретную службу на этом устройстве, к которому нужно подключиться. Сочетание сетевого адреса и порта службы называется конечной точкой, которая представлена в .NET классом EndPoint . Потомок определяется для каждого поддерживаемого EndPoint семейства адресов; для семейства IP-адресов классом является IPEndPoint.

Класс Dns предоставляет службы доменных имен для приложений, использующих интернет-службы TCP/IP. Метод GetHostEntryAsync запрашивает DNS-сервер для сопоставления понятного для пользователя доменного имени (например, "host.contoso.com") с числовым интернет-адресом (например 192.168.1.1, ). GetHostEntryAsync возвращает объект Task<IPHostEntry> , который при ожидании содержит список адресов и псевдонимов для запрошенного имени. В большинстве случаев можно использовать первый адрес из возвращенного массива AddressList. Следующий код получает объект , IPAddress содержащий IP-адрес сервера host.contoso.com.

IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];

Совет

Для ручного тестирования и отладки обычно можно использовать GetHostEntryAsync метод , чтобы получить заданное Dns.GetHostName() значение для разрешения имени localhost в IP-адрес.

Центр интернет-номеров (IANA) определяет номера портов для общих служб. Дополнительные сведения см. в разделе IANA: реестр имен служб и номеров портов транспортных протоколов). Другие службы могут использовать номера портов в диапазоне от 1024 до 65535. Следующий код объединяет IP-адрес для host.contoso.com с номером порта, чтобы создать удаленную конечную точку для подключения.

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

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

Создание Socket клиента

Создав endPoint объект , создайте сокет клиента для подключения к серверу. После подключения сокета он может отправлять и получать данные из подключения к сокету сервера.

using Socket client = new(
    ipEndPoint.AddressFamily, 
    SocketType.Stream, 
    ProtocolType.Tcp);

await client.ConnectAsync(ipEndPoint);
while (true)
{
    // Send message.
    var message = "Hi friends 👋!<|EOM|>";
    var messageBytes = Encoding.UTF8.GetBytes(message);
    _ = await client.SendAsync(messageBytes, SocketFlags.None);
    Console.WriteLine($"Socket client sent message: \"{message}\"");

    // Receive ack.
    var buffer = new byte[1_024];
    var received = await client.ReceiveAsync(buffer, SocketFlags.None);
    var response = Encoding.UTF8.GetString(buffer, 0, received);
    if (response == "<|ACK|>")
    {
        Console.WriteLine(
            $"Socket client received acknowledgment: \"{response}\"");
        break;
    }
    // Sample output:
    //     Socket client sent message: "Hi friends 👋!<|EOM|>"
    //     Socket client received acknowledgment: "<|ACK|>"
}

client.Shutdown(SocketShutdown.Both);

В приведенном выше коде C#:

  • Создает экземпляр нового Socket объекта с заданным endPoint семейством адресов экземпляров , SocketType.Streamи ProtocolType.Tcp.

  • Socket.ConnectAsync Вызывает метод с экземпляром в endPoint качестве аргумента.

  • В цикле while :

    • Кодирует и отправляет сообщение на сервер с помощью Socket.SendAsync.
    • Записывает отправленное сообщение в консоль.
    • Инициализирует буфер для получения данных с сервера с помощью Socket.ReceiveAsync.
    • response Когда является подтверждением, он записывается в консоль, и цикл завершается.
  • Наконец, client сокет вызывает Socket.Shutdown заданный SocketShutdown.Both, который завершает операции отправки и получения.

Создание Socket сервера

Чтобы создать сокет сервера, объект может прослушивать входящие подключения по любому IP-адресу, endPoint но необходимо указать номер порта. После создания сокета сервер может принимать входящие подключения и взаимодействовать с клиентами.

using Socket listener = new(
    ipEndPoint.AddressFamily,
    SocketType.Stream,
    ProtocolType.Tcp);

listener.Bind(ipEndPoint);
listener.Listen(100);

var handler = await listener.AcceptAsync();
while (true)
{
    // Receive message.
    var buffer = new byte[1_024];
    var received = await handler.ReceiveAsync(buffer, SocketFlags.None);
    var response = Encoding.UTF8.GetString(buffer, 0, received);
    
    var eom = "<|EOM|>";
    if (response.IndexOf(eom) > -1 /* is end of message */)
    {
        Console.WriteLine(
            $"Socket server received message: \"{response.Replace(eom, "")}\"");

        var ackMessage = "<|ACK|>";
        var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
        await handler.SendAsync(echoBytes, 0);
        Console.WriteLine(
            $"Socket server sent acknowledgment: \"{ackMessage}\"");

        break;
    }
    // Sample output:
    //    Socket server received message: "Hi friends 👋!"
    //    Socket server sent acknowledgment: "<|ACK|>"
}

В приведенном выше коде C#:

  • Создает экземпляр нового Socket объекта с заданным endPoint семейством адресов экземпляров , SocketType.Streamи ProtocolType.Tcp.

  • Вызывает listenerSocket.Bind метод с экземпляром в endPoint качестве аргумента для связывания сокета с сетевым адресом.

  • Метод Socket.Listen() вызывается для прослушивания входящих подключений.

  • Вызывает listener метод для Socket.AcceptAsync принятия входящего подключения к сокету handler .

  • В цикле while :

    • Вызовы Socket.ReceiveAsync для получения данных от клиента.
    • При получении данных они декодируются и записываются в консоль.
    • response Если сообщение заканчивается на <|EOM|>, подтверждение отправляется клиенту с помощью Socket.SendAsync.

Запуск примера клиента и сервера

Сначала запустите серверное приложение, а затем запустите клиентское приложение.

dotnet run --project socket-server
Socket server starting...
Found: 172.23.64.1 available on port 9000.
Socket server received message: "Hi friends 👋!"
Socket server sent acknowledgment: "<|ACK|>"
Press ENTER to continue...

Клиентское приложение отправит сообщение серверу, а сервер ответит подтверждением.

dotnet run --project socket-client
Socket client starting...
Found: 172.23.64.1 available on port 9000.
Socket client sent message: "Hi friends 👋!<|EOM|>"
Socket client received acknowledgment: "<|ACK|>"
Press ENTER to continue...

См. также раздел