Bagikan melalui


Gambaran umum TCP

Penting

Kelas Socket ini sangat direkomendasikan untuk pengguna tingkat lanjut, bukan TcpClient dan TcpListener.

Untuk bekerja dengan Protokol Kontrol Transmisi (TCP), Anda memiliki dua opsi: gunakan Socket untuk kontrol dan performa maksimum, atau gunakan kelas dan TcpClient pembantuTcpListener. TcpClient dan TcpListener dibangun di atas kelas System.Net.Sockets.Socket dan mengelola detail transfer data untuk memudahkan penggunaan.

Kelas protokol menggunakan kelas yang mendasar Socket untuk menyediakan akses sederhana ke layanan jaringan tanpa overhead mempertahankan informasi status atau mengetahui detail penyiapan soket khusus protokol. Untuk menggunakan metode asinkron Socket , Anda dapat menggunakan metode asinkron yang disediakan oleh NetworkStream kelas . Untuk mengakses fitur kelas Socket yang tidak diekspos oleh kelas protokol, Anda harus menggunakan kelas Socket.

TcpClient dan TcpListener mewakili jaringan menggunakan NetworkStream kelas . Anda menggunakan metode GetStream untuk mengembalikan aliran jaringan, lalu memanggil metode NetworkStream.ReadAsync dan NetworkStream.WriteAsync aliran. NetworkStream tidak memiliki soket dasar kelas protokol, jadi menutupnya tidak memengaruhi soket.

Gunakan TcpClient dan TcpListener

Kelas TcpClient meminta data dari sumber daya internet menggunakan TCP. Metode dan properti dari TcpClient mengabstraksi rincian untuk pembuatan Socket yang digunakan untuk meminta dan menerima data menggunakan TCP. Karena koneksi ke perangkat jarak jauh direpresentasikan sebagai aliran, data dapat dibaca dan ditulis dengan teknik penanganan aliran .NET Framework.

Protokol TCP menetapkan koneksi dengan titik akhir jarak jauh, lalu menggunakan koneksi tersebut untuk mengirim dan menerima paket data. TCP bertanggung jawab untuk memastikan bahwa paket data dikirim ke titik akhir dan dirakit dalam urutan yang benar ketika tiba.

Membuat titik akhir IP

Saat bekerja dengan System.Net.Sockets, Anda mewakili titik akhir jaringan sebagai IPEndPoint objek. IPEndPoint dibangun dengan menggunakan IPAddress dan nomor port yang terkait. Sebelum dapat memulai percakapan melalui Socket, Anda membuat pipa data antara aplikasi dan tujuan jarak jauh.

TCP/IP menggunakan alamat jaringan dan nomor port layanan untuk mengidentifikasi layanan secara unik. Alamat jaringan mengidentifikasi tujuan jaringan tertentu; nomor port mengidentifikasi layanan tertentu pada perangkat tersebut untuk disambungkan. Kombinasi alamat jaringan dan port layanan disebut titik akhir, yang diwakili dalam .NET oleh EndPoint kelas . Keturunan EndPoint didefinisikan untuk setiap keluarga alamat yang didukung; untuk keluarga alamat IP, kelasnya adalah IPEndPoint.

Kelas ini Dns menyediakan layanan nama domain ke aplikasi yang menggunakan layanan internet TCP/IP. Metode ini GetHostEntryAsync meminta server DNS untuk memetakan nama domain yang mudah digunakan (seperti "host.contoso.com") ke alamat Internet numerik (seperti 192.168.1.1). GetHostEntryAsync mengembalikan sebuah Task<IPHostEntry> yang, ketika ditunggu, berisi daftar alamat dan alias untuk nama yang diminta. Dalam kebanyakan kasus, Anda dapat menggunakan alamat pertama yang dikembalikan dalam larik AddressList. Kode berikut mengambil sebuah IPAddress yang berisi alamat IP untuk server host.contoso.com.

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

Petunjuk / Saran

** Untuk tujuan pengujian dan penelusuran kesalahan manual, Anda biasanya dapat menggunakan metode GetHostEntryAsync dengan nama host yang dihasilkan dari nilai Dns.GetHostName() untuk mengonversi nama localhost ke alamat IP. Perhatikan cuplikan kode berikut:

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

Internet Assigned Numbers Authority (IANA) menentukan nomor port untuk layanan umum. Untuk informasi selengkapnya, lihat IANA: Registri Nama Layanan dan Nomor Port Protokol Transportasi. Layanan lain dapat memiliki nomor port terdaftar dalam kisaran 1.024 hingga 65.535. Kode berikut menggabungkan alamat IP untuk host.contoso.com dengan nomor port untuk membuat titik akhir jarak jauh untuk koneksi.

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

Setelah menentukan alamat perangkat jarak jauh dan memilih port yang akan digunakan untuk koneksi, aplikasi dapat membuat koneksi dengan perangkat jarak jauh.

Membuat TcpClient

Kelas ini TcpClient menyediakan layanan TCP pada tingkat abstraksi yang lebih tinggi daripada Socket kelas . TcpClient digunakan untuk membuat koneksi klien ke host jarak jauh. Mengetahui cara mendapatkan IPEndPoint, mari kita asumsikan Anda memiliki sebuah IPAddress untuk dipasangkan dengan nomor port yang Anda inginkan. Contoh berikut menunjukkan pengaturan TcpClient untuk menyambungkan ke server waktu di port 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 🕛"

Kode C# sebelumnya:

  • Membuat IPEndPoint dari IPAddress yang diketahui dan port.
  • Menginstansiasi objek baru TcpClient.
  • Menyambungkan client ke server waktu TCP jarak jauh pada port 13 menggunakan TcpClient.ConnectAsync.
  • Menggunakan NetworkStream untuk membaca data dari host jarak jauh.
  • Mendeklarasikan buffer pembacaan sebesar 1_024 byte.
  • Membaca data dari stream ke buffer baca.
  • Menulis hasilnya sebagai string ke konsol.

Karena klien tahu bahwa pesannya kecil, seluruh pesan dapat dibaca ke buffer baca dalam satu kali operasi. Dengan pesan yang lebih besar, atau pesan dengan panjang yang tidak ditentukan, klien harus menggunakan buffer dengan lebih tepat dan membaca dalam perulangan while .

Penting

Saat mengirim dan menerima pesan, Encoding harus diketahui sebelumnya ke server dan klien. Misalnya, jika server berkomunikasi menggunakan ASCIIEncoding tetapi klien mencoba menggunakan UTF8Encoding, pesan akan salah bentuk.

Membuat TcpListener

Jenis ini TcpListener digunakan untuk memantau port TCP untuk permintaan masuk lalu membuat Socket atau TcpClient yang mengelola koneksi ke klien. Metode Start ini mengaktifkan mendengarkan, dan metode Stop menonaktifkan mendengarkan pada port. Metode ini AcceptTcpClientAsync menerima permintaan koneksi masuk dan membuat TcpClient untuk menangani permintaan, dan AcceptSocketAsync metode menerima permintaan koneksi masuk dan membuat Socket untuk menangani permintaan.

Contoh berikut menunjukkan pembuatan server waktu jaringan menggunakan TcpListener untuk memantau port TCP 13. Ketika permintaan koneksi masuk diterima, server waktu merespons dengan memberikan tanggal dan waktu saat ini dari server host.

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

Kode C# sebelumnya:

  • Membuat IPEndPoint dengan IPAddress.Any dan port.
  • Menginstansiasi objek baru TcpListener.
  • Memanggil metode Start untuk mulai mendengarkan di port.
  • Menggunakan TcpClient dari metode AcceptTcpClientAsync untuk menerima permintaan koneksi masuk.
  • Mengodekan tanggal dan waktu saat ini sebagai pesan string.
  • Menggunakan NetworkStream untuk menulis data ke klien yang tersambung.
  • Menulis pesan terkirim ke konsol.
  • Terakhir, metode Stop dipanggil untuk berhenti mendengarkan di port.

Kontrol TCP terbatas dengan kelas Socket

Baik TcpClient dan TcpListener secara internal mengandalkan kelas Socket, yang berarti apa pun yang dapat Anda lakukan dengan kelas-kelas ini dapat dicapai menggunakan soket-soket secara langsung. Bagian ini menunjukkan beberapa TcpClient dan TcpListener contoh penggunaan, bersama dengan padanan Socket yang setara secara fungsional.

Membuat soket klien

TcpClientKonstruktor default mencoba membuat soket tumpukan ganda melalui konstruktor Socket(SocketType, ProtocolType). Konstruktor ini membuat soket tumpukan ganda jika IPv6 didukung, jika tidak demikian, akan menggunakan IPv4 sebagai pengganti.

Pertimbangkan kode klien TCP berikut:

using var client = new TcpClient();

Kode klien TCP sebelumnya secara fungsional setara dengan kode soket berikut:

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

Konstruktor TcpClient(AddressFamily)

Konstruktor ini hanya menerima tiga AddressFamily nilai, jika tidak, konstruktor ini akan melemparkan ArgumentException. Nilai yang valid adalah:

Pertimbangkan kode klien TCP berikut:

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

Kode klien TCP sebelumnya secara fungsional setara dengan kode soket berikut:

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

Konstruktor TcpClient(IPEndPoint)

Setelah membuat soket, konstruktor ini juga akan mengikat ke lokalIPEndPoint yang disediakan. Properti IPEndPoint.AddressFamily digunakan untuk menentukan keluarga alamat soket.

Pertimbangkan kode klien TCP berikut:

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

Kode klien TCP sebelumnya secara fungsional setara dengan kode soket berikut:

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

Konstruktor ini akan mencoba membuat dual-stack yang mirip dengan konstruktor default dan menghubungkannya ke endpoint DNS jarak jauh yang ditentukan oleh pasangan hostname dan port.

Pertimbangkan kode klien TCP berikut:

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

Kode klien TCP sebelumnya secara fungsional setara dengan kode soket berikut:

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

Sambungkan ke server

Semua overload Connect, ConnectAsync, BeginConnect dan EndConnect pada TcpClient secara fungsional setara dengan metode Socket yang sesuai.

Pertimbangkan kode klien TCP berikut:

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

Kode di atas TcpClient setara dengan kode soket berikut:

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

Membuat soket server

Sama seperti instance TcpClient yang memiliki kesetaraan fungsional dengan padanan mentah Socket mereka, bagian ini memetakan konstruktor TcpListener ke kode soket yang sesuai. Konstruktor pertama yang perlu dipertimbangkan adalah TcpListener(IPAddress localaddr, int port).

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

Kode pendengar TCP sebelumnya secara fungsional setara dengan kode soket berikut:

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

Mulai mendengarkan di server

Metode Start() ini adalah pembungkus yang menggabungkan fungsi Socket, Bind, dan Listen().

Pertimbangkan kode pendengar TCP berikut:

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

Kode pendengar TCP sebelumnya secara fungsional setara dengan kode soket berikut:

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

Menerima koneksi server

Di balik layar, koneksi TCP masuk selalu membuat soket baru saat diterima. TcpListener dapat menerima Socket instans secara langsung (melalui AcceptSocket() atau AcceptSocketAsync()) atau dapat menerima TcpClient (melalui AcceptTcpClient() dan AcceptTcpClientAsync()).

Pertimbangkan kode berikut TcpListener :

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

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

Kode pendengar TCP sebelumnya secara fungsional setara dengan kode soket berikut:

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

Membuat NetworkStream untuk mengirim dan menerima data

Dengan TcpClient Anda perlu membuat instance NetworkStream dengan metode GetStream() agar dapat mengirim dan menerima data. Dengan Socket, Anda harus membuat NetworkStream secara manual.

Pertimbangkan kode berikut TcpClient :

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

Yang setara dengan kode soket berikut:

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

Petunjuk / Saran

Jika kode Anda tidak perlu bekerja dengan Stream instans, Anda dapat mengandalkan Socketmetode Kirim/Terima (Send, SendAsync, Receive dan ReceiveAsync) secara langsung alih-alih membuat NetworkStream.

Lihat juga