TCP-översikt
Viktigt!
Klassen Socket rekommenderas starkt för avancerade användare i stället TcpClient
för och TcpListener
.
För att arbeta med TCP (Transmission Control Protocol) har du två alternativ: använd antingen Socket för maximal kontroll och prestanda eller använd hjälpklasserna TcpClient och TcpListener . TcpClient och TcpListener bygger på System.Net.Sockets.Socket klassen och tar hand om information om överföring av data för enkel användning.
Protokollklasserna använder den underliggande Socket
klassen för att ge enkel åtkomst till nätverkstjänster utan att behöva underhålla tillståndsinformation eller känna till information om hur du konfigurerar protokollspecifika socketar. Om du vill använda asynkrona Socket
metoder kan du använda de asynkrona metoder som tillhandahålls av NetworkStream klassen. Om du vill komma åt funktioner i klassen Socket
som inte exponeras av protokollklasserna måste du använda Socket
klassen.
TcpClient
och TcpListener
representerar nätverket med hjälp av NetworkStream
-klassen. Du använder GetStream metoden för att returnera nätverksströmmen och anropa sedan strömmens NetworkStream.ReadAsync och NetworkStream.WriteAsync metoderna. Äger NetworkStream
inte protokollklassernas underliggande socket, så att stänga den påverkar inte socketen.
Använda TcpClient
och TcpListener
Klassen TcpClient begär data från en Internetresurs med hjälp av TCP. Metoderna och egenskaperna för abstrakt information för att skapa en Socket för att begära och ta emot data med hjälp av TcpClient
TCP. Eftersom anslutningen till fjärrenheten representeras som en ström kan data läsas och skrivas med .NET Framework-dataströmhanteringstekniker.
TCP-protokollet upprättar en anslutning med en fjärrslutpunkt och använder sedan anslutningen för att skicka och ta emot datapaket. TCP ansvarar för att säkerställa att datapaket skickas till slutpunkten och monteras i rätt ordning när de anländer.
Skapa en IP-slutpunkt
När du arbetar med System.Net.Socketsrepresenterar du en nätverksslutpunkt som ett IPEndPoint objekt. IPEndPoint
är konstruerad med ett IPAddress och dess motsvarande portnummer. Innan du kan starta en konversation via en Socketskapar du en datapipe mellan din app och fjärrmålet.
TCP/IP använder en nätverksadress och ett tjänstportnummer för att unikt identifiera en tjänst. Nätverksadressen identifierar ett specifikt nätverksmål. portnumret identifierar den specifika tjänst på enheten som ska anslutas till. Kombinationen av nätverksadress och tjänstport kallas för en slutpunkt, som representeras i .NET av EndPoint klassen. En underordnad EndPoint
till definieras för varje adressfamilj som stöds. För IP-adressfamiljen är IPEndPointklassen .
Klassen Dns tillhandahåller domännamnstjänster till appar som använder TCP/IP-internettjänster. Metoden GetHostEntryAsync frågar en DNS-server om du vill mappa ett användarvänligt domännamn (till exempel "host.contoso.com") till en numerisk Internetadress (till exempel 192.168.1.1
). GetHostEntryAsync
returnerar en Task<IPHostEntry>
som när den väntar innehåller en lista med adresser och alias för det begärda namnet. I de flesta fall kan du använda den första adressen som returneras i matrisen AddressList . Följande kod hämtar en IPAddress som innehåller IP-adressen för servern host.contoso.com
.
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
Dricks
För manuell testning och felsökning kan du vanligtvis använda GetHostEntryAsync metoden med det resulterande värdnamnet från Dns.GetHostName() värdet för att matcha localhost-namnet till en IP-adress. Överväg följande kodfragment:
var hostName = Dns.GetHostName();
IPHostEntry localhost = await Dns.GetHostEntryAsync(hostName);
// This is the IP address of the local machine
IPAddress localIpAddress = localhost.AddressList[0];
IANA (Internet Assigned Numbers Authority) definierar portnummer för vanliga tjänster. Mer information finns i IANA: Service Name och Transport Protocol Port Number Registry). Andra tjänster kan ha registrerade portnummer i intervallet 1 024 till 65 535. Följande kod kombinerar IP-adressen för med ett portnummer för host.contoso.com
att skapa en fjärrslutpunkt för en anslutning.
IPEndPoint ipEndPoint = new(ipAddress, 11_000);
När du har fastställt fjärrenhetens adress och valt en port som ska användas för anslutningen kan appen upprätta en anslutning till fjärrenheten.
Skapa en TcpClient
Klassen TcpClient
tillhandahåller TCP-tjänster på en högre abstraktionsnivå än Socket
klassen. TcpClient
används för att skapa en klientanslutning till en fjärrvärd. Vi antar att IPEndPoint
du har ett IPAddress
att parkoppla med önskat portnummer. I följande exempel visas hur du konfigurerar en TcpClient
för att ansluta till en tidsserver på TCP-port 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 🕛"
Föregående C#-kod:
- Skapar en
IPEndPoint
från en kändIPAddress
port och en port. - Instansiera ett nytt
TcpClient
objekt. - Ansluter
client
till den fjärranslutna TCP-tidsservern på port 13 med .TcpClient.ConnectAsync - Använder en NetworkStream för att läsa data från fjärrvärden.
- Deklarerar en läsbuffert med
1_024
byte. - Läser data från
stream
till läsbufferten. - Skriver resultatet som en sträng till konsolen.
Eftersom klienten vet att meddelandet är litet kan hela meddelandet läsas in i läsbufferten i en åtgärd. Med större meddelanden eller meddelanden med en obestämd längd bör klienten använda bufferten på ett lämpligare sätt och läsa i en while
loop.
Viktigt!
När du skickar och tar emot meddelanden bör vara Encoding känt i förväg till både server och klient. Om servern till exempel kommunicerar med men ASCIIEncoding klienten försöker använda UTF8Encodingkommer meddelandena att vara felaktiga.
Skapa en TcpListener
Typen TcpListener används för att övervaka en TCP-port för inkommande begäranden och sedan skapa antingen en Socket
eller en TcpClient
som hanterar anslutningen till klienten. Metoden Start aktiverar lyssning och Stop metoden inaktiverar lyssning på porten. Metoden AcceptTcpClientAsync accepterar inkommande anslutningsbegäranden och skapar en TcpClient
för att hantera begäran, och AcceptSocketAsync metoden accepterar inkommande anslutningsbegäranden och skapar en Socket
för att hantera begäran.
I följande exempel visas hur du skapar en nätverkstidsserver med hjälp av en TcpListener
för att övervaka TCP-port 13. När en inkommande anslutningsbegäran godkänns svarar tidsservern med aktuellt datum och tid från värdservern.
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();
}
Föregående C#-kod:
- Skapar ett
IPEndPoint
med IPAddress.Any och en port. - Instansiera ett nytt
TcpListener
objekt. - Start Anropar metoden för att börja lyssna på porten.
- Använder en
TcpClient
från AcceptTcpClientAsync -metoden för att acceptera inkommande anslutningsbegäranden. - Kodar aktuellt datum och tid som ett strängmeddelande.
- Använder en NetworkStream för att skriva data till den anslutna klienten.
- Skriver det skickade meddelandet till konsolen.
- Anropar slutligen Stop metoden för att sluta lyssna på porten.
Finite TCP-kontroll med Socket
klassen
Både TcpClient
och TcpListener
internt förlitar sig på Socket
klassen, vilket innebär att allt du kan göra med dessa klasser kan uppnås med hjälp av sockets direkt. Det här avsnittet visar flera TcpClient
och TcpListener
användningsfall, tillsammans med deras Socket
motsvarighet som är funktionellt likvärdig.
Skapa en klientsocket
TcpClient
Standardkonstruktorn försöker skapa ett dubbelstacksuttag via konstruktorn Socket(SocketType, ProtocolType). Den här konstruktorn skapar en socket med dubbla staplar om IPv6 stöds, annars återgår den till IPv4.
Överväg följande TCP-klientkod:
using var client = new TcpClient();
Den föregående TCP-klientkoden är funktionellt likvärdig med följande socketkod:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
Konstruktorn TcpClient(AddressFamily)
Konstruktorn accepterar endast tre AddressFamily
värden, annars genereras en ArgumentException. Giltiga värden är:
- AddressFamily.InterNetwork: för IPv4-socket.
- AddressFamily.InterNetworkV6: för IPv6-socket.
- AddressFamily.Unknown: detta försöker skapa en socket med dubbla staplar, på samma sätt som standardkonstruktorn.
Överväg följande TCP-klientkod:
using var client = new TcpClient(AddressFamily.InterNetwork);
Den föregående TCP-klientkoden är funktionellt likvärdig med följande socketkod:
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Konstruktorn TcpClient(IPEndPoint)
När du skapar socketen binder den här konstruktorn även till den angivna lokala IPEndPoint
. Egenskapen IPEndPoint.AddressFamily används för att fastställa socketens adressfamilj.
Överväg följande TCP-klientkod:
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5001);
using var client = new TcpClient(endPoint);
Den föregående TCP-klientkoden är funktionellt likvärdig med följande socketkod:
// 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);
Konstruktorn TcpClient(String, Int32)
Konstruktorn försöker skapa en dubbelstack som liknar standardkonstruktorn och ansluta den till den fjärranslutna DNS-slutpunkten som definieras av hostname
paret och port
.
Överväg följande TCP-klientkod:
using var client = new TcpClient("www.example.com", 80);
Den föregående TCP-klientkoden är funktionellt likvärdig med följande socketkod:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);
Anslut till servern
Alla Connect
, ConnectAsync
och BeginConnect
EndConnect
överlagringar i TcpClient
är funktionellt likvärdiga med motsvarande Socket
metoder.
Överväg följande TCP-klientkod:
using var client = new TcpClient();
client.Connect("www.example.com", 80);
Koden ovan TcpClient
motsvarar följande socketkod:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);
Skapa en server-socket
Precis som instanser med TcpClient
funktionell ekvivalens med sina råa Socket
motsvarigheter mappar TcpListener
det här avsnittet konstruktorer till motsvarande socketkod. Den första konstruktorn att tänka på är TcpListener(IPAddress localaddr, int port)
.
var listener = new TcpListener(IPAddress.Loopback, 5000);
Föregående TCP-lyssnarkod är funktionellt likvärdig med följande socketkod:
var ep = new IPEndPoint(IPAddress.Loopback, 5000);
using var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Börja lyssna på servern
Metoden Start() är en omslutning som kombinerar Socket
's Bind och Listen() funktioner.
Överväg följande TCP-lyssnarkod:
var listener = new TcpListener(IPAddress.Loopback, 5000);
listener.Start(10);
Föregående TCP-lyssnarkod är funktionellt likvärdig med följande socketkod:
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();
}
Acceptera en serveranslutning
Under huven skapar inkommande TCP-anslutningar alltid en ny socket när den godkänns. TcpListener
kan acceptera en Socket instans direkt (via AcceptSocket() eller AcceptSocketAsync()) eller acceptera en TcpClient (via AcceptTcpClient() och AcceptTcpClientAsync()).
Överväg följande TcpListener
kod:
var listener = new TcpListener(IPAddress.Loopback, 5000);
using var acceptedSocket = await listener.AcceptSocketAsync();
// Synchronous alternative.
// var acceptedSocket = listener.AcceptSocket();
Föregående TCP-lyssnarkod är funktionellt likvärdig med följande socketkod:
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();
Skapa en NetworkStream
för att skicka och ta emot data
Med TcpClient
behöver du instansiera en NetworkStream med GetStream() -metoden för att kunna skicka och ta emot data . Med Socket
måste du göra skapandet NetworkStream
manuellt.
Överväg följande TcpClient
kod:
using var client = new TcpClient();
using NetworkStream stream = client.GetStream();
Vilket motsvarar följande socketkod:
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);
Dricks
Om koden inte behöver fungera med en Stream instans kan du förlita dig på Socket
metoderna Skicka/ta emot (Send, SendAsyncReceive och ReceiveAsync) direkt i stället för att skapa en NetworkStream.