TCP-overzicht
Belangrijk
De Socket klasse wordt ten zeerste aanbevolen voor geavanceerde gebruikers, in plaats van TcpClient
en TcpListener
.
Als u wilt werken met Transmission Control Protocol (TCP), hebt u twee opties: voor Socket maximale controle en prestaties, of gebruik de TcpClient en TcpListener helperklassen. TcpClient en TcpListener zijn gebouwd op basis van de System.Net.Sockets.Socket klasse en zorgen voor de details van het overdragen van gegevens voor gebruiksgemak.
De protocolklassen gebruiken de onderliggende Socket
klasse om eenvoudige toegang tot netwerkservices te bieden zonder de overhead van het onderhouden van statusinformatie of het kennen van de details van het instellen van protocolspecifieke sockets. Als u asynchrone Socket
methoden wilt gebruiken, kunt u de asynchrone methoden van de NetworkStream klasse gebruiken. Als u toegang wilt krijgen tot functies van de Socket
klasse die niet worden weergegeven door de protocolklassen, moet u de Socket
klasse gebruiken.
TcpClient
en TcpListener
vertegenwoordig het netwerk met behulp van de NetworkStream
klasse. U gebruikt de GetStream methode om de netwerkstroom te retourneren en roept vervolgens de stream NetworkStream.ReadAsync en NetworkStream.WriteAsync methoden aan. De NetworkStream
socket van de protocolklassen is niet eigenaar van de onderliggende socket van de protocolklasse, dus het sluiten heeft geen invloed op de socket.
Gebruiken TcpClient
en TcpListener
De TcpClient klasse vraagt gegevens van een internetresource aan met behulp van TCP. De methoden en eigenschappen van TcpClient
abstracte details voor het maken van een Socket voor het aanvragen en ontvangen van gegevens met behulp van TCP. Omdat de verbinding met het externe apparaat wordt weergegeven als een stroom, kunnen gegevens worden gelezen en geschreven met technieken voor de verwerking van .NET Framework-stromen.
Het TCP-protocol brengt een verbinding tot stand met een extern eindpunt en gebruikt vervolgens die verbinding om gegevenspakketten te verzenden en te ontvangen. TCP is verantwoordelijk voor het garanderen dat gegevenspakketten naar het eindpunt worden verzonden en in de juiste volgorde worden samengesteld wanneer ze binnenkomen.
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.com
ophaalt.
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.
Maak een TcpClient
De TcpClient
klasse biedt TCP-services op een hoger abstractieniveau dan de Socket
klasse. TcpClient
wordt gebruikt om een clientverbinding met een externe host te maken. Als u weet hoe u een IPEndPoint
nummer krijgt, gaan we ervan uit dat u een IPAddress
moet koppelen aan uw gewenste poortnummer. In het volgende voorbeeld ziet u hoe u een TcpClient
verbinding kunt maken met een tijdserver op TCP-poort 13:
var ipEndPoint = new IPEndPoint(ipAddress, 13);
using TcpClient client = new();
await client.ConnectAsync(ipEndPoint);
await using NetworkStream stream = client.GetStream();
var buffer = new byte[1_024];
int received = await stream.ReadAsync(buffer);
var message = Encoding.UTF8.GetString(buffer, 0, received);
Console.WriteLine($"Message received: \"{message}\"");
// Sample output:
// Message received: "đ
8/22/2022 9:07:17 AM đ"
De voorgaande C#-code:
- Hiermee maakt u een
IPEndPoint
van een bekendeIPAddress
en poort. - Instantieer een nieuw
TcpClient
object. - Hiermee maakt u verbinding
client
met de externe TCP-tijdserver op poort 13 met behulp van TcpClient.ConnectAsync. - NetworkStream Hiermee kunt u gegevens van de externe host lezen.
- Declareert een leesbuffer van
1_024
bytes. - Leest gegevens uit de
stream
in de leesbuffer. - Hiermee schrijft u de resultaten als een tekenreeks naar de console.
Omdat de client weet dat het bericht klein is, kan het hele bericht in ÊÊn bewerking in de leesbuffer worden gelezen. Bij grotere berichten of berichten met een onbepaalde lengte moet de client de buffer beter gebruiken en in een while
lus lezen.
Belangrijk
Wanneer u berichten verzendt en ontvangt, moet u Encoding van tevoren bekend zijn bij zowel de server als de client. Als de server bijvoorbeeld communiceert met ASCIIEncoding behulp van maar de client probeert te gebruiken UTF8Encoding, worden de berichten onjuist ingedeeld.
Maak een TcpListener
Het TcpListener type wordt gebruikt om een TCP-poort te bewaken voor binnenkomende aanvragen en vervolgens een Socket
of een TcpClient
poort te maken waarmee de verbinding met de client wordt beheerd. De Start methode schakelt luisteren in en de Stop methode schakelt luisteren op de poort uit. De AcceptTcpClientAsync methode accepteert binnenkomende verbindingsaanvragen en maakt een TcpClient
om de aanvraag te verwerken. De AcceptSocketAsync methode accepteert binnenkomende verbindingsaanvragen en maakt een Socket
om de aanvraag te verwerken.
In het volgende voorbeeld ziet u hoe u een netwerktijdserver maakt met behulp van een TcpListener
server voor het bewaken van TCP-poort 13. Wanneer een binnenkomende verbindingsaanvraag wordt geaccepteerd, reageert de tijdserver met de huidige datum en tijd van de hostserver.
var ipEndPoint = new IPEndPoint(IPAddress.Any, 13);
TcpListener listener = new(ipEndPoint);
try
{
listener.Start();
using TcpClient handler = await listener.AcceptTcpClientAsync();
await using NetworkStream stream = handler.GetStream();
var message = $"đ
{DateTime.Now} đ";
var dateTimeBytes = Encoding.UTF8.GetBytes(message);
await stream.WriteAsync(dateTimeBytes);
Console.WriteLine($"Sent message: \"{message}\"");
// Sample output:
// Sent message: "đ
8/22/2022 9:07:17 AM đ"
}
finally
{
listener.Stop();
}
De voorgaande C#-code:
- Hiermee maakt u een
IPEndPoint
met IPAddress.Any en poort. - Instantieer een nieuw
TcpListener
object. - Roept de Start methode aan om te beginnen met luisteren op de poort.
- Hiermee gebruikt u een
TcpClient
van de AcceptTcpClientAsync methode om binnenkomende verbindingsaanvragen te accepteren. - Codeert de huidige datum en tijd als een tekenreeksbericht.
- NetworkStream Hiermee schrijft u gegevens naar de verbonden client.
- Hiermee schrijft u het verzonden bericht naar de console.
- Ten slotte roept u de Stop methode aan om te stoppen met luisteren op de poort.
Eindig TCP-besturingselement met de Socket
klasse
Zowel TcpClient
als TcpListener
intern vertrouwen op de Socket
klasse, wat betekent dat alles wat u met deze klassen kunt doen, rechtstreeks met sockets kan worden bereikt. In deze sectie ziet u verschillende TcpClient
en TcpListener
use cases, samen met hun Socket
tegenhanger die functioneel gelijkwaardig is.
Een clientsocket maken
TcpClient
De standaardconstructor probeert een dual-stack socket te maken via de socket-constructor (SocketType, ProtocolType). Deze constructor maakt een dual-stack socket als IPv6 wordt ondersteund, anders valt deze terug op IPv4.
Houd rekening met de volgende TCP-clientcode:
using var client = new TcpClient();
De voorgaande TCP-clientcode is functioneel gelijk aan de volgende socketcode:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
De TcpClient(AddressFamily) constructor
Deze constructor accepteert slechts drie AddressFamily
waarden, anders wordt er een ArgumentException. Geldige waarden zijn:
- AddressFamily.InterNetwork: voor IPv4-socket.
- AddressFamily.InterNetworkV6: voor IPv6-socket.
- AddressFamily.Unknown: hiermee wordt geprobeerd een dubbele stack-socket te maken, vergelijkbaar met de standaardconstructor.
Houd rekening met de volgende TCP-clientcode:
using var client = new TcpClient(AddressFamily.InterNetwork);
De voorgaande TCP-clientcode is functioneel gelijk aan de volgende socketcode:
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
De TcpClient(IPEndPoint) constructor
Bij het maken van de socket wordt deze constructor ook verbonden met de opgegeven lokaleIPEndPoint
. De IPEndPoint.AddressFamily eigenschap wordt gebruikt om de adresfamilie van de socket te bepalen.
Houd rekening met de volgende TCP-clientcode:
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5001);
using var client = new TcpClient(endPoint);
De voorgaande TCP-clientcode is functioneel gelijk aan de volgende socketcode:
// Example IPEndPoint object
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5001);
using var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(endPoint);
De TcpClient(String, Int32) constructor
Deze constructor probeert een dual-stack te maken die vergelijkbaar is met de standaardconstructor en deze te verbinden met het externe DNS-eindpunt dat is gedefinieerd door het hostname
en port
paar.
Houd rekening met de volgende TCP-clientcode:
using var client = new TcpClient("www.example.com", 80);
De voorgaande TCP-clientcode is functioneel gelijk aan de volgende socketcode:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);
Met server verbinden
Alle Connect
, ConnectAsync
BeginConnect
en EndConnect
overbelastingen in TcpClient
zijn functioneel gelijk aan de bijbehorende Socket
methoden.
Houd rekening met de volgende TCP-clientcode:
using var client = new TcpClient();
client.Connect("www.example.com", 80);
De bovenstaande TcpClient
code is gelijk aan de volgende socketcode:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);
Een serversocket maken
Net zoals TcpClient
exemplaren met functionele gelijkwaardigheid met hun onbewerkte Socket
tegenhangers, worden TcpListener
in deze sectie constructors toegewezen aan de bijbehorende socketcode. De eerste constructor die u moet overwegen, is de TcpListener(IPAddress localaddr, int port)
.
var listener = new TcpListener(IPAddress.Loopback, 5000);
De voorgaande TCP-listenercode is functioneel gelijk aan de volgende socketcode:
var ep = new IPEndPoint(IPAddress.Loopback, 5000);
using var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Beginnen met luisteren op de server
De Start() methode is een wrapper die de functies Bind en Listen() functionaliteit combineertSocket
.
Houd rekening met de volgende TCP-listenercode:
var listener = new TcpListener(IPAddress.Loopback, 5000);
listener.Start(10);
De voorgaande TCP-listenercode is functioneel gelijk aan de volgende socketcode:
var endPoint = new IPEndPoint(IPAddress.Loopback, 5000);
using var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(endPoint);
try
{
socket.Listen(10);
}
catch (SocketException)
{
socket.Dispose();
}
Een serververbinding accepteren
Onder de schermen worden binnenkomende TCP-verbindingen altijd een nieuwe socket gemaakt wanneer deze wordt geaccepteerd. TcpListener
kan een Socket exemplaar rechtstreeks (via AcceptSocket() of AcceptSocketAsync()) accepteren of een TcpClient (via AcceptTcpClient() en AcceptTcpClientAsync()) accepteren.
Houd rekening met de volgende TcpListener
code:
var listener = new TcpListener(IPAddress.Loopback, 5000);
using var acceptedSocket = await listener.AcceptSocketAsync();
// Synchronous alternative.
// var acceptedSocket = listener.AcceptSocket();
De voorgaande TCP-listenercode is functioneel gelijk aan de volgende socketcode:
var endPoint = new IPEndPoint(IPAddress.Loopback, 5000);
using var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
using var acceptedSocket = await socket.AcceptAsync();
// Synchronous alternative
// var acceptedSocket = socket.Accept();
NetworkStream
Een gegevens verzenden en ontvangen maken
U TcpClient
moet een NetworkStream instantie maken met de GetStream() methode om gegevens te kunnen verzenden en ontvangen. Met Socket
, moet u het NetworkStream
maken handmatig.
Houd rekening met de volgende TcpClient
code:
using var client = new TcpClient();
using NetworkStream stream = client.GetStream();
Dit komt overeen met de volgende socketcode:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
// Be aware that transferring the ownership means that closing/disposing the stream will also close the underlying socket.
using var stream = new NetworkStream(socket, ownsSocket: true);
Tip
Als uw code niet met een Stream exemplaar hoeft te werken, kunt u rechtstreeks vertrouwen op Socket
de methoden voor verzenden/ontvangen (Send, SendAsyncReceive en ReceiveAsync) in plaats van een NetworkStream.