Megosztás a következőn keresztül:


A TCP áttekintése

Fontos

Az Socket osztály kifejezetten ajánlott a haladó felhasználók számára ahelyett, TcpClient hogy és TcpListener.

A Transmission Control Protocol (TCP) használatához két lehetősége van: vagy a maximális vezérléshez és a teljesítményhez, Socket vagy használja a TcpClient TcpListener segédosztályokat. TcpClient és TcpListener az osztályra System.Net.Sockets.Socket épülnek, és a könnyű használat érdekében gondoskodnak az adatok átvitelének részleteiről.

A protokollosztályok az alapul szolgáló Socket osztály használatával egyszerű hozzáférést biztosítanak a hálózati szolgáltatásokhoz az állapotinformációk fenntartása vagy a protokollspecifikus szoftvercsatornák beállításának részleteinek ismerete nélkül. Az aszinkron Socket metódusok használatához használhatja az osztály által NetworkStream biztosított aszinkron metódusokat. A protokollosztályok által nem közzétett osztály funkcióinak Socket eléréséhez az osztályt Socket kell használnia.

TcpClient és TcpListener az osztály használatával képviseli a NetworkStream hálózatot. A metódussal GetStream visszaadhatja a hálózati streamet, majd meghívhatja a streamet NetworkStream.ReadAsync és NetworkStream.WriteAsync a metódusokat. A NetworkStream protokollosztályok alapjául szolgáló szoftvercsatornának nincs tulajdonosa, ezért a lezárás nem befolyásolja a szoftvercsatornát.

Használat TcpClient és TcpListener

Az TcpClient osztály TCP használatával kér adatokat egy internetes erőforrástól. Az absztrakció módszerei és tulajdonságai TcpClient a TCP használatával történő adatkéréshez és -fogadáshoz szükséges létrehozás részletei Socket . Mivel a távoli eszközhöz való kapcsolat streamként van ábrázolva, az adatok .NET-keretrendszer streamkezelési technikákkal olvashatók és írhatók.

A TCP protokoll kapcsolatot létesít egy távoli végponttal, majd ezt a kapcsolatot használja adatcsomagok küldéséhez és fogadásához. A TCP feladata annak biztosítása, hogy az adatcsomagok a végpontra érkezve a megfelelő sorrendben legyenek összeállítva.

IP-végpont létrehozása

A munka System.Net.Socketssorán egy hálózati végpontot jelöl objektumként IPEndPoint . A IPEndPoint felépítése egy IPAddress és annak megfelelő portszámmal történik. Mielőtt beszélgetést kezdeményezhet egy Socketalkalmazáson keresztül, hozzon létre egy adatcsatornát az alkalmazás és a távoli cél között.

A TCP/IP egy hálózati címet és egy szolgáltatásportszámot használ a szolgáltatás egyedi azonosításához. A hálózati cím azonosít egy adott hálózati célt; a portszám azonosítja az adott szolgáltatást azon az eszközön, amelyhez csatlakozni szeretne. A hálózati cím és a szolgáltatásport kombinációját végpontnak nevezzük, amelyet a .NET-ben az EndPoint osztály jelöl. A program minden támogatott címcsaládhoz meghatároz egy leszármazottat EndPoint ; az IP-címcsalád esetében az osztály a IPEndPoint.

Az Dns osztály tartománynév-szolgáltatásokat biztosít a TCP/IP internetszolgáltatásokat használó alkalmazások számára. A GetHostEntryAsync metódus lekérdez egy DNS-kiszolgálót egy felhasználóbarát tartománynév (például "host.contoso.com") numerikus internetcímre (például 192.168.1.1). GetHostEntryAsync visszaad egy Task<IPHostEntry> olyan értéket, amely a várt állapotban tartalmazza a kért név címeinek és aliasainak listáját. A legtöbb esetben használhatja a tömbben AddressList visszaadott első címet. A következő kód a IPAddress kiszolgáló host.contoso.comIP-címét tartalmazza.

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

Tipp.

Manuális tesztelési és hibakeresési célokra általában a GetHostEntryAsync metódust használhatja az eredményül kapott gazdagépnévvel az Dns.GetHostName() értékből a localhost név IP-címre való feloldásához. Vegye figyelembe a következő kódrészletet:

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

Az Internet Assigned Numbers Authority (IANA) a gyakori szolgáltatások portszámait határozza meg. További információ : IANA: Service Name and Transport Protocol Port Number Registry). Más szolgáltatások 1024 és 65 535 közötti tartományba tartozó regisztrált portszámokkal rendelkezhetnek. Az alábbi kód egy portszámmal egyesíti az IP-címet host.contoso.com egy távoli végpont létrehozásához egy kapcsolathoz.

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

A távoli eszköz címének meghatározása és a kapcsolathoz használandó port kiválasztása után az alkalmazás kapcsolatot létesíthet a távoli eszközzel.

Hozzon létre egy TcpClient

Az TcpClient osztály a TCP-szolgáltatásokat az osztálynál Socket magasabb absztrakciós szinten biztosítja. TcpClient egy távoli gazdagép ügyfélkapcsolatának létrehozására szolgál. Tudva, hogyan szerezhet be egy IPEndPoint, tegyük fel, hogy van egy IPAddress párosítani a kívánt port számát. Az alábbi példa egy időkiszolgálóhoz való csatlakozás beállítását TcpClient mutatja be a 13-os TCP-porton:

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

Az előző C# kód:

  • Egy ismert IPAddress és egy portból hoz létre.IPEndPoint
  • Új TcpClient objektum példányosítása.
  • Csatlakoztatja a client távoli TCP-időkiszolgálót a 13-as porton a használatával TcpClient.ConnectAsync.
  • NetworkStream A távoli gazdagépről származó adatok olvasására szolgál.
  • Bájtok olvasási pufferét 1_024 deklarálja.
  • Beolvassa az adatokat az olvasási stream pufferbe.
  • Az eredményeket sztringként írja a konzolra.

Mivel az ügyfél tudja, hogy az üzenet kicsi, a teljes üzenet beolvasható az olvasási pufferbe egyetlen műveletben. Nagyobb üzenetek vagy meghatározhatatlan hosszúságú üzenetek esetén az ügyfélnek a puffert megfelelőbben kell használnia, és egy while hurokban kell olvasnia.

Fontos

Üzenetek küldésekor és fogadásakor a kiszolgálónak és az Encoding ügyfélnek is előre tudnia kell. Ha például a kiszolgáló a használatával ASCIIEncoding kommunikál, de az ügyfél megpróbálja használni UTF8Encoding, az üzenetek helytelenül lesznek formázva.

Hozzon létre egy TcpListener

Ez TcpListener a típus a bejövő kérések TCP-portjának figyelésére szolgál, majd létrehoz egy Socket vagy egy TcpClient , az ügyfélhez való kapcsolatot kezelőt. A Start metódus lehetővé teszi a figyelés használatát, a Stop metódus pedig letiltja a port hallgatását. A AcceptTcpClientAsync metódus fogadja a bejövő kapcsolatkéréseket, és létrehoz egy TcpClient kérést a kérés kezeléséhez, a metódus pedig fogadja a AcceptSocketAsync bejövő kapcsolatkéréseket, és létrehoz egy Socket kérést a kérés kezeléséhez.

Az alábbi példa bemutatja, hogyan hozhat létre hálózati időkiszolgálót a TcpListener 13-ás TCP-port figyeléséhez. Bejövő kapcsolatkérés elfogadásakor az időkiszolgáló az aktuális dátummal és időponttal válaszol a gazdakiszolgálótól.

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

Az előző C# kód:

  • Létrehoz egy IPEndPoint with IPAddress.Any and portot.
  • Új TcpListener objektum példányosítása.
  • Meghívja a metódust Start , hogy elkezdjen figyelni a porton.
  • A metódus egyikével TcpClient fogadja a AcceptTcpClientAsync bejövő kapcsolatkéréseket.
  • Az aktuális dátumot és időt sztringüzenetként kódolja.
  • Az a NetworkStream használatával adatokat írhat a csatlakoztatott ügyfélnek.
  • Az elküldött üzenetet a konzolra írja.
  • Végül meghívja a metódust Stop , hogy ne hallgassa meg a portot.

Véges TCP-vezérlő az Socket osztálysal

Mind belsőlegTcpListener, mind TcpClient az Socket osztályra támaszkodik, ami azt jelenti, hogy minden, amit ezekkel az osztályokkal el lehet érni közvetlenül szoftvercsatornákkal. Ez a szakasz számos TcpClient használati TcpListener esetet mutat be, valamint Socket azok funkcionálisan egyenértékű megfelelőjét.

Ügyfélcsatorna létrehozása

TcpClientAz alapértelmezett konstruktor kettős veremű szoftvercsatornát próbál létrehozni a Socket(SocketType, ProtocolType) konstruktoron keresztül. Ez a konstruktor kettős veremű szoftvercsatornát hoz létre, ha az IPv6 támogatott, ellenkező esetben az IPv4-be kerül vissza.

Vegye figyelembe a következő TCP-ügyfélkódot:

using var client = new TcpClient();

Az előző TCP-ügyfélkód funkcionálisan egyenértékű a következő szoftvercsatornás kóddal:

using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

A TcpClient(AddressFamily) konstruktor

Ez a konstruktor csak három AddressFamily értéket fogad el, ellenkező esetben egy ArgumentException. Az érvényes értékek a következők:

Vegye figyelembe a következő TCP-ügyfélkódot:

using var client = new TcpClient(AddressFamily.InterNetwork);

Az előző TCP-ügyfélkód funkcionálisan egyenértékű a következő szoftvercsatornás kóddal:

using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

A TcpClient(IPEndPoint) konstruktor

A szoftvercsatorna létrehozásakor a konstruktor a megadott helyihez IPEndPointis kötődik. A IPEndPoint.AddressFamily tulajdonság a szoftvercsatorna címcsaládjának meghatározására szolgál.

Vegye figyelembe a következő TCP-ügyfélkódot:

var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5001);
using var client = new TcpClient(endPoint);

Az előző TCP-ügyfélkód funkcionálisan egyenértékű a következő szoftvercsatornás kóddal:

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

A TcpClient(String, Int32) konstruktor

Ez a konstruktor megkísérli létrehozni az alapértelmezett konstruktorhoz hasonló kettős vermet, és csatlakoztatni az és port a pár által hostname meghatározott távoli DNS-végponthoz.

Vegye figyelembe a következő TCP-ügyfélkódot:

using var client = new TcpClient("www.example.com", 80);

Az előző TCP-ügyfélkód funkcionálisan egyenértékű a következő szoftvercsatornás kóddal:

using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);

Csatlakozás kiszolgálóhoz

Az összes Connect, BeginConnect ConnectAsyncés EndConnect a TcpClient túlterhelések funkcionálisan egyenértékűek a megfelelő Socket módszerekkel.

Vegye figyelembe a következő TCP-ügyfélkódot:

using var client = new TcpClient();
client.Connect("www.example.com", 80);

A fenti TcpClient kód egyenértékű a következő szoftvercsatorna-kóddal:

using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);

Kiszolgálói szoftvercsatorna létrehozása

A nyers Socket megfelelőkkel funkcionális egyenértékűséggel rendelkező példányokhoz hasonlóan TcpClient ez a szakasz a konstruktorokat a megfelelő szoftvercsatorna-kódhoz rendeliTcpListener. Az első konstruktor, amelyet figyelembe kell venni, a TcpListener(IPAddress localaddr, int port).

var listener = new TcpListener(IPAddress.Loopback, 5000);

Az előző TCP-figyelőkód funkcionálisan egyenértékű a következő szoftvercsatornás kóddal:

var ep = new IPEndPoint(IPAddress.Loopback, 5000);
using var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

Figyelés indítása a kiszolgálón

A Start() metódus egy burkoló, amely egyesíti az 's Bind és Listen() a Socketfunkcionalitás.

Vegye figyelembe a következő TCP-figyelőkódot:

var listener = new TcpListener(IPAddress.Loopback, 5000);
listener.Start(10);

Az előző TCP-figyelőkód funkcionálisan egyenértékű a következő szoftvercsatornás kóddal:

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

Kiszolgálókapcsolat elfogadása

A kapucni alatt a bejövő TCP-kapcsolatok mindig új szoftvercsatornát hoznak létre, ha elfogadják. TcpListenerközvetlenül (keresztül vagy) elfogadhat egy Socket példányt, vagy elfogadhat egy (keresztül ésAcceptTcpClientAsync()) példányt TcpClient AcceptTcpClient().AcceptSocket() AcceptSocketAsync()

Vegye figyelembe a következő TcpListener kódot:

var listener = new TcpListener(IPAddress.Loopback, 5000);
using var acceptedSocket = await listener.AcceptSocketAsync();

// Synchronous alternative.
// var acceptedSocket = listener.AcceptSocket();

Az előző TCP-figyelőkód funkcionálisan egyenértékű a következő szoftvercsatornás kóddal:

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 Adatok küldésére és fogadására vonatkozó létrehozás

Az TcpClient adatok küldéséhez és fogadásához a metódussal GetStream() kell példányt NetworkStream létrehoznia. Ezzel a lépéssel Socketmanuálisan kell létrehoznia a létrehozást NetworkStream .

Vegye figyelembe a következő TcpClient kódot:

using var client = new TcpClient();
using NetworkStream stream = client.GetStream();

Ami egyenértékű a következő szoftvercsatorna-kóddal:

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

Tipp.

Ha a kódnak nem kell egy példánysal Stream dolgoznia, közvetlenül a küldési/fogadási metódusokra (Sendés ReceiveAsync) támaszkodhat Socketahelyett, SendAsyncReceive hogy létrehoz egy példánytNetworkStream.

Lásd még