QT TCP Sunucu Uygulaması (BÇOM Serisi – 4)

Evet QT serüvenimize devam ediyoruz arkadaşlar. Serideki diğer yazılara aşağıdaki bağlantılardan ulaşabilirsiniz:

Bir önceki yazımda sizler ile QT kullanarak, yazılımsal olarak bir TCP soket istemci uygulaması paylaşmıştım. O yazıda, QT API’si kullanarak, Grafiksel Kullanıcı Arayüzünü kod içerisinden nasıl oluşturabileceğimize bakmıştık. Aynı zamanda QT kullanarak ağ/soket programlamaya da değinmiştim. Bu yazımda da, bu istemci uygulaması ile haberleşebilecek olan, yine QT ile geliştirilmiş QT sunucu test uygulamasını paylaşacağım. Bir önceki uygulamadan farklı olarak bu yazılımdaki GKA bileşenlerini Visual Studio içerisinden QT Designer kullanarak geliştirdim (bu eklentiyi kurmak ve daha fazla bilgi edinmek için ilk yazıma bakabilirsiniz). Bu vesile ile hızlıca QT designer’a da değineceğim.

Yazılıma ilişkin örnek ekran görüntüsüne aşağıda:

Ekran görüntüsüne baktıktan sonra artık yazılıma göz atabiliriz. Öncelikli olarak yazılımın sahip olduğu kabiliyetleri kısaca sıralamak gerekirse:

  • Geliştirdiğimiz “NetworkLibrary” ve “CommonUI” alt yapısını kullanmakta,
  • Verilen port u dinleyerek, birden fazla istemci uygulamasının bağlanmasına olanak sağlamakta,
  • ASCII ve binary veri girişine ve gönderilmesine (ayrı bir QT bileşeni olarak) olanak sağlamakta,
  • Mesaj boyutu belirleme, sonuna yeni satır ekleyebilmekte,
  • Bütün istemciler ile olan haberleşmenin görüntülenmesi, kaydedilmesine olanak sağlamakta,
  • İstemciye özel mesajları filtreleme, sadece ilgili istemciye mesaj gönderme ya da ilgili istemci ile olan bağlantının koparılması,
  • Kaynak kod doxygen formatına göre dokümante edilmiş durumda(Doc\Doxygen\html dizini altında).

Proje Yapısına İlişkin Güncellemeler

Öncelikli olarak bir önceki istemci yazılımında geliştirmiş olduğumuz, ortak haberleşme kütüphanesi ve GKA bileşenlerini ayrı bir projeye taşıdım. Bu tarz birden fazla projede kullanmayı planladığınız kabiliyetleri ayrı projelerde tutmak, hem yeni geliştirme eforunuzu hem de bakım maliyetlerinizi düşürecektir. Bu anlamda iki ek projemiz oldu:

  • CommonUILibrary
    • Bu proje statik kütüphane projesi olarak oluşturuldu,
    • Her iki uygulamada da kullanmış olduğumuz IP adresi görsel bileşeni ve çok amaçlı veri giriş bileşenleri bulunuyor,
    • Bu bileşenlere ilişkin GKA’yı VS içerisinde .ui dosyalarına tıklayarak görebilir ve değiştirebilirsiniz.
  • NetworkLibrary
    • Asıl ağ haberleşmesi ile ilgili olan sınıfları içeren projemiz bu,
    • Temel olarak istemci TCP ve sunucu TCP alt sınıfları bulunuyor,
    • Bu sınıflar, arka tarafta QT tarafından sunulan QT soket sınıflarını kullanıyor olsa da, ağ haberleşme kabiliyetini daha hızlı ve kolay kullanabilmeniz adına bir takım eklentiler içermektedir. Bunların bir kısmına bu yazımın ilerleyen başlıklarında değinmeye çalışacağım.

Projenin VS içerisinde genel görünümü aşağıdaki gibidir:

Bu arada projeyi oluştururken, yaşadığınız hataları yorumlar aracılığı ile bildirebilirsiniz. Bir önceki istemci yazısındaki önerilere de göz atmayı unutmayınız.

Projenin güncel haline aşağıdaki adresten ulaşabilirsiniz:

https://github.com/yazilimperver/SimpleMultiplayerGameEngine

Qt UI Designer

Gelelim QT UI designer’a. Sunucu uygulamasına ilişkin GKA bileşenlerinin tamamını bu aracı kullanarak geliştirdim. Bütün bu GKA bileşenlerine, QTServerTestApp projesi altında bulunan QTServerTestApp.ui dosyasına çift tıklayarak ulaşabilirsiniz. Bu dosyaya çift tıkladığınızda aşağıdaki gibi bir görüntü görmenizi bekliyorum:

Hızlıca bu araç ile yapabileceklerinize değinelim. Ben burada en önemli olduğunu düşündüğüm hususlara değineceğim, daha detaylı bilgi için aracın sayfasına https://doc.qt.io/qt-5/qtdesigner-manual.html başvurabilirsiniz. Şimdi madde madde bakalım:

  • Alan 0:
    • Bu kısımda dosya menüsü ve araç çubuğu bulunmakta,
    • Dosya menüsü yanında, widget düzenleme, sinyal/slot ayarlamaları, seçim sıralaması (tab order), yerleşim ayarlamaları ve “buddy editing” diye bir seçenek bulunmakta,
    • Yerleşim ayarlamaları:
      • QT ile GKA geliştirirken iyi öğrenmeniz gereken konulardan birisi de yerleşim düzenleri “layout”‘lardır. Bunlara ne kadar aşina olursanız o kadar kolay bir GKA uygulaması geliştirebilirsiniz.
      • Ne tür seçenekleriniz olduğunu düğmelerden ve 1. paneldeki bileşenlerden görebilirsiniz. Bunlardan en sık kullanacaklarınız yatay/dikey yerleştirme, ızgara yerleştirme olacak. Bu yazımda bunların detayına girmeyeceğim, başka bir yazıda bunlara bakarız. Merak edenler için https://doc.qt.io/qt-5/designer-layouts.html# güzel bir kaynak.
      • Burada bulunan aşağıdaki ikon da mevcut seçili yerleşimi iptal etmek için kullanılır.

  • Alan 1 (“Widget Box”):
    • Bu alan, uygulamalarınızın GKA’larını oluşturmak için ihtiyaç duyacağınız temel bileşenleri içermektedir,
    • Bu bileşenlerin bir çoğu, gerekli kabiliyetleri gerçeklemek üzere çeşitli servisler ve sinyal/slot’lar sunmaktadırlar,
    • Bunların her biri için Qt Assistant ya da ilgili çevrim içi sayfaya başvurabilirsiniz, hatta çokça başvurmalısınız 🙂
    • Aşağıdaki gibi gruplandırılmıştır:
      • Yerleşim düzenleri (“Layouts”)
        • Yukarıda bahsetmiştim, genel olarak GKA bileşenlerinin yerleştirilmesi için kullanılan düzenlemeler,
      • Ayıraçlar (“Spacers”)
        • Yerleşim düzenleri ile birlikte, bileşenler arasına yatay ve dikey boşluk bırakmak için kullanılırlar,
      • Düğmeler (“Buttons”)
        • İsminden de anlaşılacağı üzere tıklanarak etkileşime girilen temel bileşenleri içerir,
      • Madde Tabanlı Görünümler (“Item Views (Model-Based”)
        • Bu grup altında, liste ve tablo benzeri veri sıralama ve görüntüleme için kullanılacak bileşenler sıralanmaktadır,
        • “Item Widgets” grubundaki bileşenlerden bunların fark ise, bu bileşenlerin QT’nin “Model-View” yaklaşımına, aslında temel olarak “Model-View-Controller” yaklaşımına, uyumlu olmalıdır. Bu sebeple, bunların kullanımı, diğer grubunkilere tercih edilmelidir,
        • Bu konu ile ilgili daha detaylı bilgi için https://doc.qt.io/qt-5/model-view-programming.html adresine göz atılabilir,
      • Madde Tabanlı Bileşenler (“Item Widgets (Item-Based”)
        • Verilerin gösterilmesi için kullanılacak olan bileşenler
      • Konteynerler (“Containers”)
        • Diğer bileşenleri, pencere içerisinde gruplandırmak için kullanılabilecek bileşenlerdir,
      • Girdi Bileşenleri (“Input Widgets”)
        • Kullanıcıdan farklı girdileri almak için kullanılabilecek olan bileşenlerdir,
      • Görüntüleme Bileşenleri (“Display Widgets”)
        • Madde tabanlı bileşenlerin yanında, veri görüntülemek için kullanılabilecek bileşenlerdir.
  • Alan 2:
    • Bu alan görsel bileşenlerinizi tasarladığınız alandır ve genel yerleşimi görmenizi sağlar,
    • Nihai görünümü görmek için ise dosya menüsü altında bulunan “Form->Preview” ve “Form->Preview in” seçeneklerini kullanabilirsiniz,
    • Burada kırmızı kutular ile gruplandırılmış bileşenler aynı yerleşim düzeni içerisinde olan bileşenlerdir,
    • Bileşenleri bir yerleşim düzenine dahil etmek için bunları pencere içerisine koyup daha sonra Ctrl ile çoklu seçim yapabilirsiniz. Bileşenleri seçtikten sonra gerek araç çubuğundaki düğmeleri ya da sağ tıkladığınızda açılan menüde bulunan “Lay out” seçeneği ile seçtiğiniz yerleşime dahil edebilirsiniz,
    • Herhangi bir yerleşime dahil olmayan bileşeni seçtiğinizde onu çevreleyen kutu koyu mavi, dahil olan bileşenler ise açık mavi renkte görünecektir,
    • GKA tasarlarken Ctrl + Z ve Ctrl + Y’yi kullanmaktan çekinmeyin.
  • Alan 3 (“Object Inspector”):
    • En çok başvurduğum alanlardan birisi de burası. Pencereye ve içerisinde bulunan bütün bileşenler burada, ağaç yapısından gösterilmektedir. Yerleşim düzenleri de burada görülebilir,
    • Burada ayrıca her bir bileşenin ismi ve sınıfını da görebilirsiniz.
  • Alan 4 (“Property Editor”):
    • Bu alan içerisinde, tasarım alanında mevcut seçili görsel bileşene ilişkin özellikleri atayıp, değiştirebilirsiniz,
    • Burada alanın üst kısmında bulunan filtreleme kutusunu da kullanmanızı tavsiye ederim,
    • Değiştirilen özellikler siyah renkte gösterilmekte,
    • Varsayılan sıralamanın yanında özellikleri isme göre de sıralayabilirsiniz,
    • Son olarak birden fazla bileşeni seçtiğinizde, bu alanda bütün seçili elemanların ortak özellikleri gösterilecektir. Bu sayede birden fazla bileşene ait özelliği bir kerede değiştirebilirsiniz.
  • Alan 5 (“Action Editor”):
    • Bu alan içerisinde, daha önce kod içerisinde yapmış olduğumuz, sinyal/slot eşleştirmelerini ve uygulama içerisindeki aksiyonları bağlama gibi aktiviteleri gerçekleştirebilirsiniz,
    • Ayrıca “Resource Browser” kısmında da uyuglama kaynakları yönetilmektedir.

Qt UI designer’a ilişkin anlatacaklarım şimdilik bu kadar. Daha önce de ifade ettiğim gibi, bu araca vakıf olmanın en iyi yolu, onu kurcalamak ve bolca kullanmak. İlgili github’tan kodları çekerek kurcalamaya başlayabilirsiniz.

https://github.com/yazilimperver/SimpleMultiplayerGameEngine

Soket Programlamaya Dair Son Notlar

Evet başlık sizleri yanıltmasın, bunları belki de en başta anlatmalıydım ama kafalarda biraz soru işaretlerinin oluşmasını her zaman hazır bilgiden daha fazla yeğlerim 🙂 Ayrıca, bir önceki istemci yazımda ifade ettiğim gibi, kod içerisinde izlenen yöntemleri bire bir buraya taşımadım. Ama yazımı sonlandırmadan da, soket tabanlı yazılım geliştirirken bir çok yazılımcının aklını kurcalayan bir kaç konuya burada kısaca değinmek istedim. Bu arada, bu hususlar sadece Qt için geçerli değil, diğer programlama dilleri ve kütüphaneleri için de geçerlidir.

  • Soket programlamada kullanılan haberleşme protokolleri temel olarak TCP (Tansmission Control Protocol) ve UDP (User Datagram Protocol) olarak ikiye ayırlır,
  • Bu iki protokolde IP (Internet Protokol) üzerine kuruludur. Şimdi bu iki protokole ilişkin geneş bir takım bilgilere bakalım:
    • TCP:
      • TCP tabanlı haberleşme, en yaygın kullanılan protokollerden birisidir ve bağlantı tabanlı olarak nitelendirilir,
      • Bu protokolde gönderilen paketlerin aynı sırada ulaştırılacağı garanti altına alınmıştır,
      • Gönderilen veriler hatalı olma durumuna karşı kontrol edilirler, ayrıca bağlantı ile ilgili durumdan taraflar haberdar edilirler,
      • Yukarıda anlatılanlardan anlaşılacağı üzere TCP, güvenirlik üzerine kurulmuştur.
    • UDP:
      • UDP, TCP’den farklı olarak, hata durumlarının kontrolü  ya da sıra kontrol gibi durumlar göz ardı edilir, geliştiriciye bırakılır,
      • Gönderilen paketlerin sıralaması ya da ulaşıp/ulaşmadığı garantisi verilmez,
      • UDP genel olarak hızın, güvenirlikten daha önemli olduğu durumlarda kullanılır,
      • Örneğin, çevrim içi oyunlar ya da canlı yayınlar gibi,
      • Ağırlıklı olarak UDP haberleşmesine, ayrıca bir TCP kanalı da eşlik eder.
    • Ayrıca aşağıdaki resimler de, bu iki protokole ilişkin güzel bilgiler içeriyor:
    • Image result for tcp vs udpUDP
  • Şimdi gelelim bu iki protokolün biz yazılımcılar açısından barındırdığı hususlara:
    • Soketler de dosyalar gibi özel bir tanımlayıcıya sahiptirler ve bu işletim sistemi tarafından sağlanır,
    • Soketler oluşturulurken her zaman bir port ile ilişkilendirilirler ve aldıkları değer 0-65535 arasında değişir,
    • Bir bilgisayar da aynı port numarasında sahip iki soket oluşturulamaz,
    • Bazı uygulamalar, servisler belirli portları kullanırlar. Soketleri oluştururken bunlara dikkat etmenizde fayda var. Bunlara bakmak için https://www.webopedia.com/quick_ref/portnumbers.asp adresine göz atabilirsiniz,
    • Sunucu soketler, dinleme işlemini yine belirtilen bu port üzerinden yaparlar ve istemciler de, sunuculara bağlanmak için bu portu kullanırlar. Birden fazla istemci bu porta bağlanır,
    • Şimdi gelelim bir milyonluk soruya, aynı bilgisayarda aynı porta ilişkin birden fazla soket oluşturulamıyorsa, birden fazla istemci nasıl oluyorda bu soketlere bağlanıyor. Hemen açıklayalım,
      • Sunucu bir portu dinlemeye alır,
      • Bir istemci o porta bağlanır,
      • İşletim sistemi o sırada kullanılmayan bir portu bu bağlantı için ayırır ve istemci ile olan haberleşme artık bu port üzerinden yapılır (uygulama içerisinde IConnectedClient sınıfı tam da bu amaç için oluşturuldu),
      • Örneğin 80. portu dinleyen bir sunucuya bağlantı olduğu zaman aşağıdaki gibi bir durum ortaya çıkar:

      • Burada ifade edilmesi gereken bir diğer durumda, sunucu istemci haberleşmelerinde, genelde istemci için port atamaya ihtiyaç olmaz (tabi yine de atayabilirsiniz) ve çoğu Soket API’si de soket oluştururken port istemeyen bir arayüz sunarlar,
    • UDP’de ise durum biraz farklı. Aslında bakarsanız, ben yazılımlarımda UDP kullandığım zaman istemci/sunucu yerine genelde akran (peer-to-peer) ifadesini kullanıyorum. Çünkü, protokolün doğası buna daha yatkın,
    • UDP’de herhangi bir bağlantı oluşturulmaz, fakat veriyi alan taraf gelen paket içerisinden, veriyi gönderen akrana ilişkin adres bilgilerini temin edebilir (bunun için çoğu soket kütüphanesi API sunmaktadır).
    • Bu iki haberleşmeye ilişkin izlenen adımlar aşağıdaki figürlerde özetlenmektedir:
      • TCP Sunucu/İstemci haberleşmesi 
      • PIC
      • UDP haberleşmesi
      • PIC

 

the client does not form a connection with the server like in TCP and instead just sends a datagram. Similarly, the server need not accept a connection and just waits for datagrams to arrive. Datagrams upon arrival contain the address of sender which the server uses to send data to the correct client.

Sonuç

Evet arkadaşlar, bir yazımızın daha sonuna geldik. Bu yazı ile birlikte TCP istemci ve sunucu uygulamalarımızı geliştirmeyi tamamladık. Bundan sonra biraz daha oyunlara yönelik geliştirmeler yaparak devam edeceğiz. Bir de ara ara, birim test, sürekli entegrasyon gibi konulara değineceğiz. Daha önce de ifade ettiğim gibi, dodu lütfen indirin, inceleyin, hunharca değiştirin ve kullanın.

Bu arada bu iki uygulamayı birleştirip TCP Soket test uygulaması olarak sizler ile paylaşacağım. Tabi bir kaç küçük güncelleme ile birlikte 😉

O zamana kadar iyi kodlamalar diliyorum.

Kaynaklar

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.