C ile TCP Server/Client Uygulaması


Konunun anlaşılması için ilk önce bazı kavramların üzerinden geçmemiz gerekiyor.

Socket Nedir?

Socket’ler, Applicatin Layer ile Transport Layer arasında bağlantıyı kuran yazılımsal alanlardır. Socketler networkler içerisinde 2 farklı process arasında bağlantı kurabilmemizi sağlarlar. Örneğin tarayıcımızdan bir web sitesine girdiğimizde, arka tarafta uygun socket ler hazırlanır ve o web sitesiyle haberleşme sağlanır. Sadece web sitelerine girdiğimizde socket ler kullanılmaz, ayrıca kendi bilgisayarımızda çalışan iki ayrı uygulamada socket ler yardımı ile haberleşebilir.

Socket’ler aslında Unix File Descriptor‘ a benzer. Socket oluştuğunda bize file descriptor verilir. Bu file decriptor yardımı ile haberleşmemizi sağlayabiliyoruz.

Binding

Server.c dosyasındaki kodlarda bind komutunu göreceksiniz. Peki nedir binding? Aslında çok basit.

Server ve client‘ın haberleşebilmesi için client ve server’ın birbirlerinin adresine ve portlarına ihtiyaçları vardır. Binding, sockete adres ve port numarasının atanmasına denmektedir. Peki neden “Server.c” de bind komutu kullanılırken, “Client.c” de connect komutu kullanılıyor? Aralarındaki fark nedir?

Bind komutu local adresi bağlamakta kullanılır, connect komutu remote adresi bağlamakta kullanılır.

Gerekli Header Dosyaları

Bildiğiniz gibi C dilinde include diye bir komut yer alıyor. Bu komut sayesinde ihtiyacımız olan kütüphaneyi projemize dahil edip, o kütüphane içerisindeki ihtiyacımız olan şeyi kullanabiliyoruz.

Socket oluşturmak için gerekli olan struct ları barındıran bazı header dosyalarımız var. Bunları include etmemiz gerekiyor:

  • sys/socket.h
  • netinet/in.h

Örnek TCP Server/Client uygulamasının kodlarını buradan bulabilirsiniz.

Kodları ve komutları açıklamaya çalışayım.

  • _serverfd ve newsocket değişkenlerinin int tanımlanmasındaki sebep bir socket oluştuğunda bize geri döndürüğü değer file descriptor numarasıdır. Bu yüzden geri dönüş değerini “int” veri türünde saklamak gerekiyor.
  • _sockaddr_in_ struct’ı bizim socket i istediğimiz gibi şekillendirmemizi sağlıyor. Örneğin sin_family değişkeni IPv4 la mı yada IPv6 le mi çalışacağımızı belirler.
  • socket() fonksiyonu bizim için socket oluşturur ve geri dönüş değeri olarak file descriptor numarası döndürür.
  • setsockopt() fonksiyonu opsiyonel bir fonksiyondur. “Address already in use” hatasını almamamız için kullanılır.
  • bind() fonksiyonu yukarıda bahsettiğim binding işlemini yapar.
  • listen() fonksiyonu, server ın maksimum kabul edeceği bağlantı sayısını belirler.
  • accept() fonksiyonu, bağlantı kuran clientı kabul edip, client la haberleşebilmesi için yeni bir socket açar.
  • read ve send, socket ten gelen veriyi okumamızı ve göndermemizi sağlar.
  • connect fonksiyonu bağlanmamızı sağlar.

Dikkat edilmesi gereken birkaç yer var.

  • Socket() fonksiyonuna IPv4 ile çalışmak istersek AF_INET, IPv6 ile çalışmak istersek AF_INET6 domainini vermemiz gerekiyor. TCP protokolünü kullanmak istersek SOCK_STREAM, UDP protokolünü kullanmak istersek SOCK_DGRAM.
  • Socket oluştururken başarılı bir şekilde oluşup oluşmadığını kontrol etmemiz gerekiyor, aksi halde sorunlara yol açabilir.
  • Her socket yalnızca bir portu dinleyebildiği için binding yaparken kullanılmayan portlara atama yapmalısınız.
  • accept fonksiyonu yeni bir socket oluşturur ve haberleşme yaparken bu socket üzerinden yapılması gerekir.
  • read komutu socketteki veriyi bizim belirlediğimiz değişkene atar(buffer). Bu yüzden buffer overflow saldırılarına dikkat etmemiz gerekiyor.
  • Eş zamanlı olarak birden fazla client la haberleşmek için multithreading kullanılmalıdır.

Bir sonraki blog yazımda görüşmek üzere.

Kaynak

https://www.geeksforgeeks.org/tcp-server-client-implementation-in-c/

Be First to Comment

Leave a Reply

Your email address will not be published.