Přehled protokolu TCP
Důležité
Třída Socket je vysoce doporučena pro pokročilé uživatele místo TcpClient
a TcpListener
.
Pro práci s protokolem TCP (Transmission Control Protocol) máte dvě možnosti: buď pro Socket maximální kontrolu a výkon, nebo použijte TcpClient pomocné třídy.TcpListener TcpClient a TcpListener jsou postaveny na System.Net.Sockets.Socket třídě a starají se o podrobnosti přenosu dat pro snadné použití.
Třídy protokolu používají základní Socket
třídu k poskytování jednoduchého přístupu k síťovým službám bez režie na údržbu informací o stavu nebo znalost podrobností o nastavení soketů specifických pro protokol. Chcete-li použít asynchronní Socket
metody, můžete použít asynchronní metody poskytované NetworkStream třídou. Chcete-li získat přístup k funkcím Socket
třídy, které nejsou vystaveny třídami protokolu, je nutné použít Socket
třídu.
TcpClient
a TcpListener
představuje síť pomocí NetworkStream
třídy. Tuto metodu GetStream použijete k vrácení síťového streamu a následnému volání streamu NetworkStream.ReadAsync a NetworkStream.WriteAsync metod. Základní NetworkStream
soket třídy protokolu nevlastní, takže uzavření nemá vliv na soket.
Použití TcpClient
a TcpListener
Třída TcpClient požaduje data z internetového prostředku pomocí protokolu TCP. Metody a vlastnosti abstrahují TcpClient
podrobnosti pro vytvoření Socket pro vyžádání a příjem dat pomocí protokolu TCP. Vzhledem k tomu, že připojení ke vzdálenému zařízení je reprezentováno jako datový proud, lze data číst a zapisovat pomocí technik zpracování datových proudů rozhraní .NET Framework.
Protokol TCP vytvoří připojení ke vzdálenému koncovému bodu a pak toto připojení použije k odesílání a přijímání datových paketů. TCP zodpovídá za zajištění, aby se datové pakety posílaly do koncového bodu a sestavovaly se ve správném pořadí, když dorazí.
Vytvoření koncového bodu PROTOKOLU IP
Při práci s System.Net.Socketsobjektem představujete koncový bod IPEndPoint sítě. Vytvoří IPEndPoint
se s odpovídajícím číslem portu a jeho odpovídajícím číslem IPAddress portu. Než budete moct zahájit konverzaci prostřednictvím Socketaplikace, vytvoříte mezi aplikací a vzdáleným cílem datový kanál.
TCP/IP používá síťovou adresu a číslo portu služby k jednoznačné identifikaci služby. Síťová adresa identifikuje konkrétní cíl sítě; číslo portu identifikuje konkrétní službu na daném zařízení, ke které se má připojit. Kombinace síťové adresy a portu služby se nazývá koncový bod, který je reprezentován v .NET EndPoint třídou. Potomek EndPoint
je definován pro každou podporovanou řadu adres; pro řadu IP adres je IPEndPointtřída .
Třída Dns poskytuje služby pro názvy domén aplikací, které používají internetové služby TCP/IP. Metoda GetHostEntryAsync se dotazuje serveru DNS na mapování uživatelsky přívětivého názvu domény (například "host.contoso.com") na číselnou internetovou adresu (například 192.168.1.1
). GetHostEntryAsync
Task<IPHostEntry>
vrátí hodnotu, která při čekání obsahuje seznam adres a aliasů požadovaného názvu. Ve většině případů můžete použít první adresu vrácenou AddressList v poli. Následující kód získá IPAddress obsahující IP adresu serveru host.contoso.com
.
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
Tip
Pro účely ručního testování a ladění můžete obvykle použít metodu GetHostEntryAsync s výsledným názvem hostitele z Dns.GetHostName() hodnoty k překladu názvu místního hostitele na IP adresu. Vezměte v úvahu následující fragment kódu:
var hostName = Dns.GetHostName();
IPHostEntry localhost = await Dns.GetHostEntryAsync(hostName);
// This is the IP address of the local machine
IPAddress localIpAddress = localhost.AddressList[0];
Autorita IANA (Internet Assigned Numbers Authority) definuje čísla portů pro běžné služby. Další informace najdete v tématu IANA: Název služby a registr čísel portů přenosového protokolu). Ostatní služby můžou mít registrovaná čísla portů v rozsahu 1 024 až 65 535. Následující kód kombinuje IP adresu s host.contoso.com
číslem portu a vytvoří vzdálený koncový bod pro připojení.
IPEndPoint ipEndPoint = new(ipAddress, 11_000);
Po určení adresy vzdáleného zařízení a výběru portu, který se má pro připojení použít, může aplikace navázat připojení ke vzdálenému zařízení.
Vytvořte soubor TcpClient
Třída TcpClient
poskytuje služby TCP na vyšší úrovni abstrakce než Socket
třída. TcpClient
slouží k vytvoření připojení klienta ke vzdálenému hostiteli. Když budete vědět, jak získat , IPEndPoint
předpokládejme, že máte IPAddress
párování s požadovaným číslem portu. Následující příklad ukazuje nastavení TcpClient
připojení k časovému serveru na portu TCP 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 🕛"
Předchozí kód jazyka C#:
- Vytvoří ze
IPEndPoint
známéhoIPAddress
portu a portu. - Vytvořte instanci nového
TcpClient
objektu. client
Připojí ke vzdálenému časovému serveru TCP na portu 13 pomocí TcpClient.ConnectAsync.- NetworkStream Používá ke čtení dat ze vzdáleného hostitele.
- Deklaruje vyrovnávací paměť
1_024
pro čtení bajtů. - Čte data z
stream
vyrovnávací paměti pro čtení. - Zapíše výsledky jako řetězec do konzoly.
Vzhledem k tomu, že klient ví, že je zpráva malá, může být celá zpráva načtena do vyrovnávací paměti pro čtení v jedné operaci. U větších zpráv nebo zpráv s nedeterminovat délkou by měl klient použít vyrovnávací paměť vhodnější a číst ve smyčce while
.
Důležité
Při odesílání a příjmu zpráv by mělo být předem známo jak pro server, Encoding tak pro klienta. Pokud například server komunikuje pomocí ASCIIEncoding , ale klient se pokusí použít UTF8Encoding, zprávy budou poškozeny.
Vytvořte soubor TcpListener
Tento TcpListener typ se používá k monitorování portu TCP pro příchozí požadavky a pak vytvoří Socket
buď port TCP, nebo který TcpClient
spravuje připojení k klientovi. Metoda Start umožňuje naslouchání a Stop metoda zakáže naslouchání na portu. Metoda AcceptTcpClientAsync přijímá příchozí žádosti o připojení a vytvoří TcpClient
požadavek pro zpracování a AcceptSocketAsync metoda přijímá příchozí požadavky na připojení a vytvoří Socket
žádost o zpracování.
Následující příklad ukazuje vytvoření síťového časového serveru pomocí monitoru TcpListener
portu TCP 13. Když je přijat požadavek na příchozí připojení, časový server odpoví aktuálním datem a časem z hostitelského serveru.
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();
}
Předchozí kód jazyka C#:
- Vytvoří s příponou
IPEndPoint
IPAddress.Any a portem. - Vytvořte instanci nového
TcpListener
objektu. - Zavolá metodu, Start která začne naslouchat na portu.
- Používá metodu
TcpClient
AcceptTcpClientAsync pro příjem příchozích požadavků na připojení. - Zakóduje aktuální datum a čas jako řetězcovou zprávu.
- Používá k zápisu NetworkStream dat do připojeného klienta.
- Zapíše odeslanou zprávu do konzoly.
- Nakonec zavolá metodu Stop , která zastaví naslouchání na portu.
Finite TCP control with the Socket
class
Obě TcpClient
i TcpListener
interně spoléhají na Socket
třídu, což znamená, že cokoli, co s těmito třídami můžete dělat, lze dosáhnout přímo pomocí soketů. Tato část ukazuje několik TcpClient
případů použití TcpListener
spolu s jejich Socket
protějškem, který je funkčně ekvivalentní.
Vytvoření klientského soketu
TcpClient
Výchozí konstruktor se pokusí vytvořit soket s duálním zásobníkem prostřednictvím konstruktoru Socket(SocketType, ProtocolType). Tento konstruktor vytvoří soket se dvěma zásobníky, pokud je podporován protokol IPv6, jinak se vrátí zpět na protokol IPv4.
Zvažte následující kód klienta TCP:
using var client = new TcpClient();
Předchozí kód klienta TCP je funkčně ekvivalentní následujícímu kódu soketu:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
Konstruktor TcpClient(AddressFamily)
Tento konstruktor přijímá pouze tři AddressFamily
hodnoty, jinak vyvolá výjimku ArgumentException. Platné hodnoty jsou:
- AddressFamily.InterNetwork: pro soket IPv4.
- AddressFamily.InterNetworkV6: pro soket IPv6.
- AddressFamily.Unknown: Pokusí se vytvořit soket se dvěma zásobníky, podobně jako výchozí konstruktor.
Zvažte následující kód klienta TCP:
using var client = new TcpClient(AddressFamily.InterNetwork);
Předchozí kód klienta TCP je funkčně ekvivalentní následujícímu kódu soketu:
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Konstruktor TcpClient(IPEndPoint)
Při vytváření soketu tento konstruktor také vytvoří vazbu k zadanému místnímu IPEndPoint
. Vlastnost IPEndPoint.AddressFamily slouží k určení rodiny adres soketu.
Zvažte následující kód klienta TCP:
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5001);
using var client = new TcpClient(endPoint);
Předchozí kód klienta TCP je funkčně ekvivalentní následujícímu kódu soketu:
// 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);
Konstruktor TcpClient(String, Int32)
Tento konstruktor se pokusí vytvořit duální zásobník podobný výchozímu konstruktoru a připojí ho ke vzdálenému koncovému bodu DNS definovanému parametrem a port
páremhostname
.
Zvažte následující kód klienta TCP:
using var client = new TcpClient("www.example.com", 80);
Předchozí kód klienta TCP je funkčně ekvivalentní následujícímu kódu soketu:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);
Připojit k serveru
Všechny Connect
, ConnectAsync
BeginConnect
a EndConnect
přetížení v TcpClient
jsou funkčně ekvivalentní odpovídající Socket
metody.
Zvažte následující kód klienta TCP:
using var client = new TcpClient();
client.Connect("www.example.com", 80);
Výše uvedený TcpClient
kód je ekvivalentní následujícímu kódu soketu:
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("www.example.com", 80);
Vytvoření serverového soketu
Podobně jako TcpClient
instance, které mají funkční ekvivalenci se svými nezpracovanými Socket
protějšky, tato část mapuje TcpListener
konstruktory na odpovídající kód soketu. Prvním konstruktorem, který je třeba vzít v TcpListener(IPAddress localaddr, int port)
úvahu, je .
var listener = new TcpListener(IPAddress.Loopback, 5000);
Předchozí kód naslouchacího procesu TCP je funkčně ekvivalentní následujícímu kódu soketu:
var ep = new IPEndPoint(IPAddress.Loopback, 5000);
using var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Zahájení naslouchání na serveru
Metoda Start() je obálka kombinující Socket
's Bind a Listen() funkce.
Zvažte následující kód naslouchacího procesu TCP:
var listener = new TcpListener(IPAddress.Loopback, 5000);
listener.Start(10);
Předchozí kód naslouchacího procesu TCP je funkčně ekvivalentní následujícímu kódu soketu:
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();
}
Přijetí připojení k serveru
Pod kapotou příchozí připojení TCP vždy vytváří nový soket při přijetí. TcpListener
může přijmout Socket instanci přímo (prostřednictvím AcceptSocket() nebo AcceptSocketAsync()) nebo může přijmout TcpClient (prostřednictvím AcceptTcpClient() a AcceptTcpClientAsync()).
Vezměte v úvahu následující TcpListener
kód:
var listener = new TcpListener(IPAddress.Loopback, 5000);
using var acceptedSocket = await listener.AcceptSocketAsync();
// Synchronous alternative.
// var acceptedSocket = listener.AcceptSocket();
Předchozí kód naslouchacího procesu TCP je funkčně ekvivalentní následujícímu kódu soketu:
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();
Vytvoření zprávy NetworkStream
pro odesílání a přijímání dat
S TcpClient
potřebujete vytvořit instanci s metodou NetworkStream GetStream() , aby bylo možné odesílat a přijímat data . V Socket
případě, že musíte vytvoření provést NetworkStream
ručně.
Vezměte v úvahu následující TcpClient
kód:
using var client = new TcpClient();
using NetworkStream stream = client.GetStream();
To je ekvivalentní následujícímu kódu soketu:
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
Pokud váš kód nepotřebuje pracovat s Stream instancí, můžete místo vytvoření NetworkStreamspoléhat přímo na Socket
metody Send/Receive (ReceiveSendSendAsyncaReceiveAsync) metody Send/Receive .