Delen via


Sockets gebruiken om gegevens via TCP te verzenden en te ontvangen

Voordat u een socket kunt gebruiken om te communiceren met externe apparaten, moet de socket worden geïnitialiseerd met protocol- en netwerkadresgegevens. De constructor voor de Socket klasse heeft parameters die de adresfamilie, het sockettype en het protocoltype opgeven die door de socket worden gebruikt om verbindingen te maken. Wanneer u een clientsocket verbindt met een serversocket, gebruikt de client een IPEndPoint object om het netwerkadres van de server op te geven.

Een IP-eindpunt maken

Wanneer u werkt System.Net.Sockets, vertegenwoordigt u een netwerkeindpunt als een IPEndPoint object. Het IPEndPoint is samengesteld met een IPAddress en het bijbehorende poortnummer. Voordat u een gesprek kunt starten via een Socket, maakt u een gegevenspijp tussen uw app en de externe bestemming.

TCP/IP maakt gebruik van een netwerkadres en een servicepoortnummer om een service uniek te identificeren. Het netwerkadres identificeert een specifieke netwerkbestemming; het poortnummer identificeert de specifieke service op dat apparaat waarmee verbinding moet worden gemaakt. De combinatie van netwerkadres en servicepoort wordt een eindpunt genoemd, dat wordt weergegeven in .NET door de EndPoint klasse. Er wordt een afstammeling van EndPoint gedefinieerd voor elke ondersteunde adresfamilie; voor de IP-adresfamilie is IPEndPointde klasse.

De Dns klasse biedt domeinnaamservices voor apps die gebruikmaken van TCP/IP-internetservices. De GetHostEntryAsync methode voert een query uit op een DNS-server om een gebruiksvriendelijke domeinnaam (zoals 'host.contoso.com') toe te wijzen aan een numeriek internetadres (zoals 192.168.1.1). GetHostEntryAsync retourneert een Task<IPHostEntry> lijst met adressen en aliassen voor de aangevraagde naam wanneer dit wordt verwacht. In de meeste gevallen kunt u het eerste adres gebruiken dat in de AddressList matrix wordt geretourneerd. Met de volgende code wordt een IPAddress met het IP-adres voor de server host.contoso.comophaalt.

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

Tip

Voor handmatige tests en foutopsporing kunt u doorgaans de GetHostEntryAsync methode gebruiken met de resulterende hostnaam van de Dns.GetHostName() waarde om de localhost-naam om te zetten in een IP-adres. Bekijk het volgende codefragment:

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

De Internet Assigned Numbers Authority (IANA) definieert poortnummers voor algemene services. Zie IANA: Service Name and Transport Protocol Port Number Registry) voor meer informatie. Andere services kunnen poortnummers hebben geregistreerd in het bereik van 1024 tot 65.535. De volgende code combineert het IP-adres voor host.contoso.com met een poortnummer om een extern eindpunt voor een verbinding te maken.

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

Na het bepalen van het adres van het externe apparaat en het kiezen van een poort die moet worden gebruikt voor de verbinding, kan de app verbinding maken met het externe apparaat.

Socket Een client maken

Wanneer het endPoint object is gemaakt, maakt u een clientsocket om verbinding te maken met de server. Zodra de socket is verbonden, kan deze gegevens verzenden en ontvangen van de serversocketverbinding.

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

De voorgaande C#-code:

  • Instantieert een nieuw Socket object met een bepaalde endPoint instantieadresfamilie, de SocketType.Stream, en ProtocolType.Tcp.

  • Roept de Socket.ConnectAsync methode aan met het endPoint exemplaar als argument.

  • In een while lus:

    • Codeert en verzendt een bericht naar de server met behulp van Socket.SendAsync.
    • Hiermee schrijft u het verzonden bericht naar de console.
    • Initialiseert een buffer voor het ontvangen van gegevens van de server met behulp van Socket.ReceiveAsync.
    • Wanneer het response een bevestiging is, wordt deze naar de console geschreven en wordt de lus afgesloten.
  • Ten slotte worden de client socket-aanroepen Socket.Shutdown gegeven SocketShutdown.Both, waardoor zowel verzend- als ontvangstbewerkingen worden afgesloten.

Socket Een server maken

Als u de serversocket wilt maken, kan het endPoint object luisteren naar binnenkomende verbindingen op elk IP-adres, maar moet het poortnummer worden opgegeven. Zodra de socket is gemaakt, kan de server binnenkomende verbindingen accepteren en communiceren met clients.

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

De voorgaande C#-code:

  • Instantieert een nieuw Socket object met een bepaalde endPoint instantieadresfamilie, de SocketType.Stream, en ProtocolType.Tcp.

  • De listener methode wordt aangeroepen Socket.Bind met het endPoint exemplaar als argument om de socket te koppelen aan het netwerkadres.

  • De Socket.Listen() methode wordt aangeroepen om te luisteren naar binnenkomende verbindingen.

  • De listener methode wordt aangeroepen Socket.AcceptAsync om een binnenkomende verbinding op de handler socket te accepteren.

  • In een while lus:

    • Oproepen Socket.ReceiveAsync voor het ontvangen van gegevens van de client.
    • Wanneer de gegevens worden ontvangen, worden deze gedecodeerd en naar de console geschreven.
    • Als het response bericht eindigt, <|EOM|>wordt er een bevestiging naar de client verzonden met behulp van de Socket.SendAsync.

De voorbeeldclient en -server uitvoeren

Start eerst de servertoepassing en start vervolgens de clienttoepassing.

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

De clienttoepassing verzendt een bericht naar de server en de server reageert met een bevestiging.

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

Zie ook