Partilhar via


Usar soquetes para enviar e receber dados por TCP

Antes de poder usar um soquete para se comunicar com dispositivos remotos, o soquete deve ser inicializado com informações de protocolo e endereço de rede. O construtor da Socket classe tem parâmetros que especificam a família de endereços, o tipo de soquete e o tipo de protocolo que o soquete usa para fazer conexões. Ao conectar um soquete de cliente a um soquete de servidor, o cliente usará um IPEndPoint objeto para especificar o endereço de rede do servidor.

Criar um ponto de extremidade IP

Ao trabalhar com System.Net.Socketso , você representa um ponto de extremidade de rede como um IPEndPoint objeto. O IPEndPoint é construído com um e seu número de IPAddress porta correspondente. Antes de iniciar uma conversa por meio de um Socket, crie um pipe de dados entre seu aplicativo e o destino remoto.

O TCP/IP usa um endereço de rede e um número de porta de serviço para identificar exclusivamente um serviço. O endereço de rede identifica um destino de rede específico; O número da porta identifica o serviço específico nesse dispositivo ao qual se conectar. A combinação de endereço de rede e porta de serviço é chamada de ponto de extremidade, que é representado no .NET pela EndPoint classe. Um descendente de é definido para cada família de endereços suportada, para a família de EndPoint endereços IP, a classe é IPEndPoint.

A Dns classe fornece serviços de nome de domínio para aplicativos que usam serviços de Internet TCP/IP. O GetHostEntryAsync método consulta um servidor DNS para mapear um nome de domínio amigável (como "host.contoso.com") para um endereço numérico da Internet (como 192.168.1.1). GetHostEntryAsync Retorna um Task<IPHostEntry> que, quando aguardado, contém uma lista de endereços e aliases para o nome solicitado. Na maioria dos casos, você pode usar o primeiro endereço retornado na AddressList matriz. O código a seguir obtém um IPAddress contendo o endereço IP para o servidor host.contoso.com.

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

Gorjeta

Para fins de teste manual e depuração, você normalmente pode usar o GetHostEntryAsync método com o nome de host resultante do valor para resolver o nome do Dns.GetHostName() host local para um endereço IP. Considere o seguinte trecho de código:

var hostName = Dns.GetHostName();
IPHostEntry localhost = await Dns.GetHostEntryAsync(hostName);
// This is the IP address of the local machine
IPAddress localIpAddress = localhost.AddressList[0];

A Internet Assigned Numbers Authority (IANA) define números de porta para serviços comuns. Para obter mais informações, consulte IANA: Service Name and Transport Protocol Port Number Registry). Outros serviços podem ter números de porta registrados na faixa de 1.024 a 65.535. O código a seguir combina o endereço IP para host.contoso.com com um número de porta para criar um ponto de extremidade remoto para uma conexão.

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

Depois de determinar o endereço do dispositivo remoto e escolher uma porta para usar para a conexão, o aplicativo pode estabelecer uma conexão com o dispositivo remoto.

Criar um Socket cliente

Com o endPoint objeto criado, crie um soquete de cliente para se conectar ao servidor. Uma vez que o soquete está conectado, ele pode enviar e receber dados da conexão de soquete do servidor.

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);

O código C# anterior:

  • Instancia um novo Socket objeto com uma determinada endPoint família de endereços de instâncias, o SocketType.Stream, e ProtocolType.Tcp.

  • Chama o Socket.ConnectAsync método com a endPoint instância como um argumento.

  • Em um while loop:

    • Codifica e envia uma mensagem para o servidor usando Socket.SendAsynco .
    • Grava a mensagem enviada no console.
    • Inicializa um buffer para receber dados do servidor usando Socket.ReceiveAsynco .
    • Quando o response é uma confirmação, ele é gravado no console e o loop é encerrado.
  • Finalmente, as client chamadas Socket.Shutdown de soquete dadas SocketShutdown.Both, que desliga as operações de envio e recebimento.

Criar um Socket servidor

Para criar o soquete do servidor, o endPoint objeto pode escutar conexões de entrada em qualquer endereço IP, mas o número da porta deve ser especificado. Uma vez que o soquete é criado, o servidor pode aceitar conexões de entrada e se comunicar com os clientes.

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|>"
}

O código C# anterior:

  • Instancia um novo Socket objeto com uma determinada endPoint família de endereços de instâncias, o SocketType.Stream, e ProtocolType.Tcp.

  • O listener chama o Socket.Bind método com a endPoint instância como um argumento para associar o soquete com o endereço de rede.

  • O Socket.Listen() método é chamado para escutar conexões de entrada.

  • O listener chama o Socket.AcceptAsync método para aceitar uma conexão de entrada no handler soquete.

  • Em um while loop:

    • Chamadas Socket.ReceiveAsync para receber dados do cliente.
    • Quando os dados são recebidos, eles são decodificados e gravados no console.
    • Se a response mensagem terminar com <|EOM|>, uma confirmação será enviada ao cliente usando o Socket.SendAsync.

Execute o cliente e o servidor de exemplo

Inicie o aplicativo de servidor primeiro e, em seguida, inicie o aplicativo cliente.

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...

O aplicativo cliente enviará uma mensagem para o servidor e o servidor responderá com uma confirmação.

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...

Consulte também