Gereksinimler ve Ön Hazırlık
Bu projeyi geliştirmek için sisteminizde .NET 8 veya daha güncel bir sürümün yüklü olması önerilir. Geliştirme ortamı olarak Visual Studio 2022 veya VS Code tercih edebilirsiniz. Socket programlama, düşük seviyeli bir ağ iletişimi olduğu için işletim sistemi düzeyinde bazı izinlere ihtiyaç duyabilir.
- SDK: .NET 8.0 veya üzeri.
- IDE: Visual Studio 2022 veya JetBrains Rider.
- Temel Bilgi: C# temel sözdizimi ve
async/awaityapısına aşinalık.
TCP Sunucu (Server) Kurulumu Nasıl Yapılır?
Sunucu, belirli bir portu dinleyerek istemcilerden gelen bağlantı isteklerini bekleyen yapıdır. TcpListener sınıfı, bu süreci yönetmek için en verimli yoldur. Sunucunun her zaman açık kalması ve birden fazla istemciyi kabul edebilmesi için asenkron bir yapı kurmalıyız.
using System.Net;
using System.Net.Sockets;
using System.Text;
// Sunucuyu 127.0.0.1 (Localhost) ve 5000 portunda başlatıyoruz
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 5000);
server.Start();
Console.WriteLine("Sunucu başlatıldı, bağlantı bekleniyor...");
// İstemciyi kabul et
TcpClient client = await server.AcceptTcpClientAsync();
Console.WriteLine("İstemci bağlandı!");
Yukarıdaki kod, sunucuyu yerel ağda dinlemeye başlatır. AcceptTcpClientAsync metodu, bir istemci bağlanana kadar bekler (blocking). Bağlantı kurulduğunda, iletişim için bir TcpClient nesnesi döndürülür.
İstemci (Client) Tarafı Nasıl Oluşturulur?
İstemci, sunucunun IP adresine ve portuna bağlanmaya çalışan taraftır. Bağlantı kurulduktan sonra veri akışı sağlamak için NetworkStream kullanılır. Bu akış, hem okuma hem de yazma işlemleri için temel kanaldır.
using System.Net.Sockets;
using System.Text;
// Sunucuya bağlan
TcpClient client = new TcpClient();
await client.ConnectAsync("127.0.0.1", 5000);
Console.WriteLine("Sunucuya bağlanıldı.");
// Veri gönderimi
NetworkStream stream = client.GetStream();
string message = "Merhaba Sunucu!";
byte[] data = Encoding.UTF8.GetBytes(message);
await stream.WriteAsync(data, 0, data.Length);
Bu kod bloğunda, TcpClient nesnesi ile sunucuya bağlantı sağlanır. Encoding.UTF8.GetBytes metodu, string veriyi ağ üzerinden iletilebilecek byte dizisine dönüştürür. WriteAsync ile veri sunucuya iletilir.
Veri Alışverişi ve İletişim Protokolü
Socket programlamada veriler byte dizileri halinde gönderilir. Bu nedenle, sunucu ve istemci arasında bir "protokol" belirlemek gerekir. Örneğin, verinin sonuna bir "bitiş karakteri" eklemek veya gönderilecek verinin uzunluğunu önce iletmek yaygın yöntemlerdir.
// Sunucu tarafında veri okuma
byte[] buffer = new byte[1024];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine($"Gelen mesaj: {receivedMessage}");
Bu örnekte, 1024 byte'lık bir tampon (buffer) kullanılarak gelen veri okunur. ReadAsync metodu, ağdan gelen veriyi belleğe alır ve biz de bunu Encoding.UTF8.GetString ile tekrar anlamlı bir metne dönüştürürüz.
Socket Programlama Yöntemleri Karşılaştırması
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| TcpListener (TCP) | Veri kaybı olmaz, güvenilir. | Daha yavaş, yüksek gecikme. |
| UdpClient (UDP) | Çok hızlı, düşük gecikme. | Veri kaybı olabilir, güvensiz. |
Güvenlik ve Hata Yönetimi
Kritik Uyarı: Socket programlama ham veri ile çalıştığı için XSS veya SQL Injection gibi saldırılara doğrudan maruz kalmazsınız; ancak, gelen veriyi doğrulamadan (validation) işlemek büyük güvenlik açıklarına yol açabilir. Asla gelen veriyi doğrudan bir veritabanı sorgusunda veya dosya yolunda kullanmayın. Üretim ortamında SSL/TLS (SslStream) kullanarak veriyi şifrelemeyi ihmal etmeyin.
Hata yönetimi için try-catch bloklarını kullanmak zorunludur. Ağ bağlantıları her an kopabilir; bu nedenle her işlem bir hata riski taşır.
try {
// Ağ işlemleri
} catch (SocketException ex) {
Console.WriteLine($"Ağ hatası oluştu: {ex.Message}");
} catch (Exception ex) {
Console.WriteLine($"Beklenmedik hata: {ex.Message}");
}
Sıkça Sorulan Sorular
Socket bağlantısı neden kopar?
Bağlantı kopmaları genellikle ağ kesintileri, sunucunun kapanması veya istemcinin zaman aşımına (timeout) uğraması nedeniyle gerçekleşir. Bağlantı durumunu kontrol eden bir "Keep-Alive" mekanizması kurmak bu sorunu azaltır.
Aynı anda birden fazla istemciyi nasıl yönetirim?
Sunucu tarafında her yeni bağlantı için bir Task.Run veya asenkron bir görev (thread) başlatarak her istemciyi ayrı bir döngüde yönetebilirsiniz.
Veri şifreleme nasıl yapılır?
SslStream sınıfını kullanarak, ham NetworkStream verisini TLS protokolü ile sarmalayabilir ve uçtan uca şifreli bir iletişim kurabilirsiniz.
Port çakışması nedir?
Bir port (örneğin 5000), aynı anda sadece bir uygulama tarafından dinlenebilir. Eğer "Address already in use" hatası alıyorsanız, başka bir uygulamanın o portu kullandığını bilmelisiniz.
TCP mi yoksa UDP mi seçmeliyim?
Eğer verinin eksiksiz ulaşması önemliyse (dosya transferi, mesajlaşma) TCP; hızın veriden önemli olduğu durumlarda (oyun verisi, canlı yayın) UDP tercih edilmelidir.
Socket Uygulamalarında Performans Optimizasyonu ve Ölçeklendirme
Socket tabanlı uygulamalarınız büyüdükçe, her bir istemci için ayrı bir thread (iş parçacığı) oluşturmak sistem kaynaklarını tüketebilir. Modern C# uygulamalarında, yüksek performanslı ağ iletişimi için Asynchronous Programming Model (APM) yerine Task-based Asynchronous Pattern (TAP) kullanılması önerilir. Bu yaklaşım, sunucunun binlerce bağlantıyı çok daha az bellek tüketimiyle yönetmesini sağlar.
Async/Await ile Ölçeklenebilir Sunucu Yapısı
Aşağıdaki örnek, TcpListener sınıfını kullanarak bağlantıları engelleyici (blocking) olmayan bir şekilde nasıl kabul edebileceğinizi gösterir:
public async Task StartServerAsync(int port)
{
TcpListener listener = new TcpListener(IPAddress.Any, port);
listener.Start();
while (true)
{
TcpClient client = await listener.AcceptTcpClientAsync();
_ = HandleClientAsync(client); // Fire-and-forget yöntemiyle istemciyi yönet
}
}
private async Task HandleClientAsync(TcpClient client)
{
using (NetworkStream stream = client.GetStream())
{
byte[] buffer = new byte[1024];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
// Veri işleme mantığı burada yer alır
}
}
Socket Uygulamalarında Hata Ayıklama ve İzleme
Ağ programlamada karşılaşılan en büyük zorluk, bağlantı hatalarının nedenini tespit etmektir. Uygulamanızın canlı ortamda kararlı çalışması için aşağıdaki stratejileri uygulamanız önerilir:
- Keep-Alive Paketleri: Bağlantının hala aktif olup olmadığını anlamak için belirli aralıklarla "ping" paketleri gönderin.
- Logging (Günlükleme): Her bağlantı açılışını, kapanışını ve oluşan istisnaları (Exception) mutlaka merkezi bir log dosyasına kaydedin.
- Buffer Taşması Kontrolü: Gelen verinin boyutunu mutlaka kontrol edin. Beklenenden büyük paketler, bellek saldırılarına (DoS) yol açabilir.
Wireshark ile Paket Analizi
Kodunuzun ağ üzerinde gerçekten ne gönderdiğini görmek için Wireshark gibi araçlar kullanın. Uygulamanızın yerel portunu (örneğin 8080) filtreleyerek, TCP el sıkışma (handshake) sürecini ve veri paketlerinin parçalanma durumunu gözlemleyebilirsiniz. Bu, özellikle "Nagle algoritması" gibi TCP optimizasyonlarının veri iletim hızınızı etkileyip etkilemediğini anlamanızı sağlar.
İpucu: Eğer uygulamanızda çok yüksek veri trafiği varsa, Socket.NoDelay = true; ayarını kullanarak Nagle algoritmasını devre dışı bırakabilir ve küçük paketlerin gecikmeden gönderilmesini sağlayabilirsiniz.
Sonuç
C# ile socket programlama, ağ mimarilerini anlamak için en temel ve güçlü araçtır. Bu rehberde, bir sunucunun nasıl dinleme yapacağını, istemcinin nasıl bağlanacağını ve verilerin nasıl güvenli bir şekilde aktarılacağını öğrendiniz. Bir sonraki adım olarak, çoklu istemci desteği sunan bir "Chat Server" uygulaması geliştirmeyi deneyebilirsiniz. Unutmayın, ağ programlamada en önemli kural, her zaman bağlantının kopabileceğini varsayarak kod yazmaktır.
Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Ticari veya kritik sistemlerde kullanılacak ağ uygulamalarında, modern güvenlik standartları, veri doğrulama ve şifreleme protokolleri (SSL/TLS) mutlaka uygulanmalıdır.


Yorumlar (0)
Yorum Yaz