Aracılığıyla paylaş


TCP'ye genel bakış

Önemli

İleri düzey kullanıcılar için Socket sınıfı, TcpClient ve TcpListener yerine şiddetle tavsiye edilir.

İletim Denetim Protokolü (TCP) ile çalışmak için iki seçeneğiniz vardır: maksimum denetim ve performans için Socket kullanın veya TcpClient ve TcpListener yardımcı sınıflarını kullanın. TcpClient ve TcpListener sınıfının en üstünde System.Net.Sockets.Socket oluşturulur ve kullanım kolaylığı için veri aktarımının ayrıntılarıyla ilgilenir.

Protokol sınıfları, durum bilgilerini koruma veya protokole özgü yuvaları ayarlama ayrıntılarını öğrenme yükü olmadan ağ hizmetlerine basit erişim sağlamak için temel sınıfı Socket kullanır. Asenkron Socket yöntemleri kullanmak için, NetworkStream sınıfı tarafından sağlanan asenkron yöntemleri kullanabilirsiniz. Protokol sınıfları tarafından kullanıma sunulmayan sınıfın Socket özelliklerine erişmek için sınıfını Socket kullanmanız gerekir.

TcpClient ve TcpListener, NetworkStream sınıfını kullanarak ağı temsil eder. yöntemini kullanarak GetStream ağ akışını döndürecek ve ardından akışın NetworkStream.ReadAsync ve NetworkStream.WriteAsync yöntemlerini çağıracaksınız. NetworkStream, protokol sınıflarının temel aldığı yuvaya sahip olmadığından, yuvayı kapatmak soketi etkilemez.

Kullanın TcpClient ve TcpListener

sınıfı, TcpClient TCP kullanarak bir internet kaynağından veri istemektedir. Oluşturma için TcpClient detaylarını soyutlayan yöntemler ve özellikler Socket, TCP kullanarak veri talep etme ve alma işlemleri içindir. Uzak cihaza bağlantı bir akış olarak temsil edildiğinden, veriler .NET Framework akış işleme teknikleri ile okunabilir ve yazılabilir.

TCP protokolü, uzak uç noktayla bir bağlantı kurar ve ardından veri paketlerini gönderip almak için bu bağlantıyı kullanır. TCP, veri paketlerinin uç noktaya gönderilmesini ve ulaştıklarında doğru sırada bir araya getirildiğinden emin olmakla sorumludur.

IP uç noktası oluşturma

ile System.Net.Socketsçalışırken bir ağ uç noktasını nesne olarak IPEndPoint temsil edebilirsiniz. IPEndPoint, IPAddress ve karşılık gelen bağlantı noktası numarası ile oluşturulur. aracılığıyla Socketbir konuşma başlatabilmeniz için önce uygulamanızla uzak hedef arasında bir veri kanalı oluşturursunuz.

TCP/IP, bir hizmeti benzersiz olarak tanımlamak için bir ağ adresi ve hizmet bağlantı noktası numarası kullanır. Ağ adresi belirli bir ağ hedefini tanımlar; bağlantı noktası numarası, o cihazdaki bağlanacak hizmeti tanımlar. Ağ adresi ve hizmet bağlantı noktası birleşimi, sınıfı tarafından EndPoint .NET'te temsil edilen uç nokta olarak adlandırılır. Desteklenen her adres ailesi için EndPoint alt öğesi tanımlanır; IP adresi ailesi için sınıf IPEndPoint'dir.

sınıfı, Dns TCP/IP internet hizmetlerini kullanan uygulamalara etki alanı adı hizmetleri sağlar. yöntemi, GetHostEntryAsync kullanıcı dostu bir etki alanı adını ("host.contoso.com") sayısal bir İnternet adresiyle (örneğin 192.168.1.1) eşlemek için bir DNS sunucusunu sorgular. GetHostEntryAsync ile Task<IPHostEntry>, beklendiğinde istenen ad için adresler ve diğer adların listesini içeren bir değer döndürür. Çoğu durumda, dizide AddressList döndürülen ilk adresi kullanabilirsiniz. Aşağıdaki kod, sunucusunun IPAddressIP adresini içeren bir host.contoso.com alır.

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

İpucu

Manuel test ve hata ayıklama amacıyla, Dns.GetHostName() değerinden elde edilen ana bilgisayar adıyla GetHostEntryAsync yöntemini kullanarak genellikle localhost adını bir IP adresine çözebilirsiniz. Aşağıdaki kod parçacığını göz önünde bulundurun:

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

İnternet Atanan Numaralar Yetkilisi (IANA), ortak hizmetler için bağlantı noktası numaralarını tanımlar. Daha fazla bilgi için bkz . IANA: Hizmet Adı ve Aktarım Protokolü Bağlantı Noktası Numarası Kayıt Defteri). Diğer hizmetler 1.024 ile 65.535 arasında kayıtlı bağlantı noktası numaralarına sahip olabilir. Aşağıdaki kod, bağlantı için uzak uç nokta oluşturmak üzere host.contoso.com ip adresini bir bağlantı noktası numarasıyla birleştirir.

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

Uzak cihazın adresini belirledikten ve bağlantı için kullanılacak bağlantı noktasını seçtikten sonra uygulama uzak cihazla bağlantı kurabilir.

TcpClient oluşturun

Bu TcpClient sınıf, Socket sınıfından daha yüksek bir soyutlama düzeyinde TCP hizmetleri sağlar. TcpClient uzak bir ana bilgisayara istemci bağlantısı oluşturmak için kullanılır. Bir IPEndPoint almak için nasıl bilgi sahibi olunacağını bildiğinizi varsayalım, istediğiniz bağlantı noktası numarasıyla eşleştirmek istediğiniz bir IPAddress var. Aşağıdaki örnek, 13 numaralı TCP bağlantı noktasındaki bir zaman sunucusuna bağlanmak için TcpClient'ün nasıl ayarlandığını göstermektedir.

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

Yukarıdaki C# kodu:

  • Bilinen IPEndPoint ve bağlantı noktasından bir IPAddress oluşturur.
  • Yeni bir TcpClient nesne örneği oluşturun.
  • client kullanarak, 13 numaralı port üzerinden uzak TCP zaman sunucusuna TcpClient.ConnectAsync ile bağlanır.
  • Uzak konaktan verileri okumak için bir NetworkStream kullanır.
  • 1_024 baytlık bir okuma arabelleği tanımlar.
  • 'den stream okuma arabelleğine veri okur.
  • Sonuçları konsola dize olarak yazar.

İstemci iletinin küçük olduğunu bildiği için, iletinin tamamı tek bir işlemde okuma arabelleğine okunabilir. Daha büyük iletilerde veya belirsiz uzunluktaki iletilerde, istemci arabelleği daha uygun bir şekilde kullanmalı ve bir döngü içerisinde while okumalıdır.

Önemli

İleti gönderirken ve alırken, Encoding hem sunucuya hem de istemciye önceden bilinmesi gerekir. Örneğin, sunucu ASCIIEncoding kullanarak iletişim kurar ancak istemci UTF8Encoding kullanmayı denerse, iletiler hatalı biçimlendirilmiş olur.

TcpListener oluşturun

Türü TcpListener , gelen istekler için bir TCP bağlantı noktasını izlemek ve ardından istemci bağlantısını yöneten bir Socket veya bir TcpClient oluşturmak için kullanılır. Start yöntemi dinlemeyi etkinleştirir ve Stop yöntem bağlantı noktasında dinlemeyi devre dışı bırakır. AcceptTcpClientAsync yöntemi gelen bağlantı isteklerini kabul eder ve isteği işlemek için bir TcpClient oluşturur ve AcceptSocketAsync yöntem gelen bağlantı isteklerini kabul eder ve isteği işlemek için bir Socket oluşturur.

Aşağıdaki örnek, bir TcpListener kullanarak 13 numaralı TCP bağlantı noktasını izleyen bir ağ zaman sunucusunun nasıl oluşturulacağını göstermektedir. Gelen bağlantı isteği kabul edildiğinde, zaman sunucusu konak sunucudan geçerli tarih ve saatle yanıt verir.

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

Yukarıdaki C# kodu:

  • IPAddress.Any ve bağlantı noktası ile bir IPEndPoint oluşturur.
  • Yeni bir TcpListener nesne örneği oluşturun.
  • Start yöntemini bağlantı noktasında dinlemeye başlamak için çağırır.
  • Gelen bağlantı isteklerini kabul etmek için AcceptTcpClientAsync yönteminden bir TcpClient kullanır.
  • Geçerli tarih ve saati dize iletisi olarak kodlar.
  • Bağlı istemciye veri yazmak için bir NetworkStream kullanır.
  • Gönderilen iletiyi konsola yazar.
  • Son olarak, Stop yöntemini çağırarak bağlantı noktasında dinlemeyi durdurur.

Socket sınıfı ile sonlu TCP kontrolü

TcpClient ve TcpListener, dahili olarak Socket sınıfını kullanır; yani bu sınıflarla yapabileceğiniz her şey, doğrudan socket'ler kullanılarak gerçekleştirilebilir. Bu bölümde, işlevsel olarak eşdeğer olan karşılıklarıyla TcpClient birlikte birkaç TcpListener ve Socket kullanım örneği gösterilmektedir.

İstemci yuvası oluşturun

TcpClient varsayılan yapıcısı, Socket(SocketType, ProtocolType) yapıcısı aracılığıyla bir çift yığın soketi oluşturmaya çalışır. Bu oluşturucu, IPv6 destekleniyorsa çift yığınlı bir yuva oluşturur, aksi takdirde IPv4'e geri döner.

Aşağıdaki TCP istemci kodunu göz önünde bulundurun:

using var client = new TcpClient();

Yukarıdaki TCP istemci kodu işlevsel olarak aşağıdaki yuva koduna eşdeğerdir:

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

TcpClient(AddressFamily) Oluşturucu

Bu oluşturucu yalnızca üç AddressFamily değer kabul eder, aksi takdirde bir ArgumentExceptionoluşturur. Geçerli değerler:

Aşağıdaki TCP istemci kodunu göz önünde bulundurun:

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

Yukarıdaki TCP istemci kodu işlevsel olarak aşağıdaki yuva koduna eşdeğerdir:

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

TcpClient(IPEndPoint) Oluşturucu

Soket oluşturulduktan sonra, bu oluşturucu sağlanan yerel adrese de bağlanacak. IPEndPoint.AddressFamily özelliği, yuvanın adres ailesini belirlemek için kullanılır.

Aşağıdaki TCP istemci kodunu göz önünde bulundurun:

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

Yukarıdaki TCP istemci kodu işlevsel olarak aşağıdaki yuva koduna eşdeğerdir:

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

TcpClient(String, Int32) Oluşturucu

Bu oluşturucu, varsayılan oluşturucuya benzer şekilde bir çift yığın oluşturmaya ve bağlantıuzaktaki DNS uç noktasına, hostname ve port çifti ile tanımlanan, bağlamaya çalışacaktır.

Aşağıdaki TCP istemci kodunu göz önünde bulundurun:

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

Yukarıdaki TCP istemci kodu işlevsel olarak aşağıdaki yuva koduna eşdeğerdir:

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

Sunucuya bağlan

içindeki tüm Connect, ConnectAsync, BeginConnect ve EndConnect aşırı yüklemeleri, TcpClient içindeki karşılık gelen Socket yöntemlerle işlevsel olarak eşdeğerdir.

Aşağıdaki TCP istemci kodunu göz önünde bulundurun:

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

Yukarıdaki TcpClient kod aşağıdaki yuva koduyla eşdeğerdir:

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

Sunucu yuvası oluşturma

TcpClient örneklerinin ham Socket karşılıklarıyla işlevsel eşdeğerliği gibi, bu bölüm TcpListener oluşturucularını ilgili soket koduyla eşler. dikkate alınması gereken ilk oluşturucudur TcpListener(IPAddress localaddr, int port).

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

Yukarıdaki TCP dinleyici kodu, işlevsel olarak aşağıdaki yuva koduyla eşdeğerdir:

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

Sunucuda dinlemeye başlama

Start() yöntemi, Socket, Bind, ve Listen() işlevlerini birleştiren bir sarmalayıcıdır.

Aşağıdaki TCP dinleyici kodunu göz önünde bulundurun:

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

Yukarıdaki TCP dinleyici kodu, işlevsel olarak aşağıdaki yuva koduyla eşdeğerdir:

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

Sunucu bağlantısını kabul etme

Teknik detayına bakıldığında, gelen TCP bağlantıları kabul edildiğinde her zaman yeni bir socket oluşturur. TcpListenerbir Socket örneği doğrudan kabul edebilir (veya AcceptSocket()aracılığıylaAcceptSocketAsync()) veya bir TcpClient (ve AcceptTcpClient()aracılığıylaAcceptTcpClientAsync()) kabul edebilir.

Aşağıdaki TcpListener kodu göz önünde bulundurun:

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

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

Yukarıdaki TCP dinleyici kodu, işlevsel olarak aşağıdaki yuva koduyla eşdeğerdir:

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

Veri göndermek ve almak için bir NetworkStream oluşturun

TcpClient ile veri gönderip alabilmek için GetStream() yöntemiyle bir NetworkStream örneği oluşturmanız gerekir. Socket ile NetworkStream oluşturma işlemini el ile yapmanız gerekir.

Aşağıdaki TcpClient kodu göz önünde bulundurun:

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

Bu, aşağıdaki yuva koduna eşdeğerdir:

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

İpucu

Kodunuzun bir Stream örneğiyle çalışmasına gerek yoksa, doğrudan Socket'in Gönder/Al yöntemlerine (Send, SendAsync, Receive ve ReceiveAsync) güvenebilir ve NetworkStream oluşturmak yerine bunları kullanabilirsiniz.

Ayrıca bkz.