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 TcpListener pembantuTcpClient. TcpClient dan TcpListener dibangun di atas System.Net.Sockets.Socket kelas dan mengurus detail transfer data untuk kemudahan 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 yang Socket
tidak diekspos oleh kelas protokol, Anda harus menggunakan Socket
kelas .
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 TcpClient
abstrak detail untuk membuat Socket 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 IPAddress dan nomor port yang sesuai. 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
Task<IPHostEntry>
mengembalikan 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 mendapatkan alamat IP yang IPAddress berisi untuk server host.contoso.com
.
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
Tip
Untuk tujuan pengujian dan penelusuran kesalahan manual, Anda biasanya dapat menggunakan GetHostEntryAsync metode dengan nama host yang dihasilkan dari Dns.GetHostName() nilai untuk menyelesaikan 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: Nama Layanan dan Registri 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 untuk dipasangkan dengan nomor port yang IPAddress
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:
IPEndPoint
Membuat dari port dan yang diketahuiIPAddress
.- Membuat instans objek baru
TcpClient
. - Menyambungkan
client
ke server waktu TCP jarak jauh pada port 13 menggunakan TcpClient.ConnectAsync. - NetworkStream Menggunakan untuk membaca data dari host jarak jauh.
- Mendeklarasikan buffer
1_024
byte baca. - Membaca data dari
stream
ke dalam buffer baca. - Menulis hasilnya sebagai string ke konsol.
Karena klien tahu bahwa pesan kecil, seluruh pesan dapat dibaca ke dalam buffer baca dalam satu 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 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:
IPEndPoint
Membuat dengan IPAddress.Any dan port.- Membuat instans objek baru
TcpListener
. - Start Memanggil metode untuk mulai mendengarkan di port.
TcpClient
Menggunakan dari AcceptTcpClientAsync metode untuk menerima permintaan koneksi masuk.- Mengodekan tanggal dan waktu saat ini sebagai pesan string.
- NetworkStream Menggunakan untuk menulis data ke klien yang tersambung.
- Menulis pesan terkirim ke konsol.
- Terakhir, memanggil Stop metode untuk berhenti mendengarkan di port.
Kontrol TCP terbatas dengan Socket
kelas
Baik TcpClient
dan TcpListener
secara internal mengandalkan Socket
kelas, yang berarti apa pun yang dapat Anda lakukan dengan kelas-kelas ini dapat dicapai menggunakan soket secara langsung. Bagian ini menunjukkan beberapa TcpClient
dan TcpListener
kasus penggunaan, bersama dengan rekan mereka Socket
yang setara secara fungsional.
Membuat soket klien
TcpClient
Konstruktor default mencoba membuat soket tumpukan ganda melalui konstruktor Socket(SocketType, ProtocolType). Konstruktor ini membuat soket tumpukan ganda jika IPv6 didukung, jika tidak, konstruktor ini akan kembali ke IPv4.
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:
- AddressFamily.InterNetwork: untuk soket IPv4.
- AddressFamily.InterNetworkV6: untuk soket IPv6.
- AddressFamily.Unknown: ini akan mencoba membuat soket tumpukan ganda, mirip dengan konstruktor default.
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 lokal yang disediakan . IPEndPoint
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 menyambungkannya ke titik akhir DNS jarak jauh yang hostname
ditentukan oleh pasangan 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 Connect
kelebihan beban TcpClient
, ConnectAsync
, BeginConnect
dan EndConnect
secara fungsional setara dengan metode yang Socket
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 TcpClient
instans yang memiliki kesetaraan fungsional dengan mitra mentah Socket
mereka, bagian ini memetakan TcpListener
konstruktor ke kode soket yang sesuai. Konstruktor pertama yang perlu dipertimbangkan TcpListener(IPAddress localaddr, int port)
adalah .
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 ini Start() adalah pembungkus yang menggabungkan Socket
fungsionalitas 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 bawah tenda, 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 instans NetworkStream dengan GetStream() metode untuk dapat mengirim dan menerima data . Dengan Socket
, Anda harus melakukan NetworkStream
pembuatan 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);
Tip
Jika kode Anda tidak perlu bekerja dengan Stream instans, Anda dapat mengandalkan Socket
metode Kirim/Terima (Send, SendAsync, Receive dan ReceiveAsync) secara langsung alih-alih membuat NetworkStream.