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 determinadaendPoint
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 determinadaendPoint
família de endereços de instâncias, o SocketType.Stream, e ProtocolType.Tcp.O
listener
chama o Socket.Bind método com aendPoint
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 nohandler
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...