Herkese selamlar dostlar. Bu konumuz oldukça eğlenceli bir konu olacak. Merak edip üzerine yoğunlaştığım bir konu vardı. Oyun sunucularına uzaktan erişerek sunuculardaki yeniden başlatma, dosya işlemleri ekleme çıkarma, kanal başlatma kapatma vb. işlemler komutlar aracılığıyla gerçekleştirilmektedir. Peki bu sunucular nasıl bir mantık ile çalışır, karşı taraf bağlanmak isterse kullanıcı adı ve şifre isteme işlemleri nasıl gerçekleşir? Bunları merak ederek yola çıktım. Özellikle Metin2, Knight Online gibi oyunlarda bu sunucular çokça kullanılmaktadır.
Dilerseniz Kodlara geçelim. Bu aşamalar C++ dili ile yazılmış olup, iostream, string, thread, vector, algorithm, winsock2.h, ws2tcpip.h, fstream, clocale kütüphanelerinden yararlanılmıştır.
Öncelikle yukarıda görmüş olduğumuz kod bloğunda yorum satırları mevcut, fakat ben detaylıca açıklamasını yapacağım. Winsock (Windows Sockets) kütüphanesi, bize Windows işletim sistemi üzerinde ağ olaylarını yönetebilmemize olanak tanımaktadır. Soket oluşturma "socket()", bağlantı kurma ve dinleme "bind(), listen(), accept()", veri gönderme ve alma "send(), recv()", bağlantı kapatma "closesocket()" gibi daha birçok fonksiyon ve işlevsellik tanımaktadır.
Şimdi gelelim kodlarımıza. "setlocale" fonksiyonu, Türkçe karakter sorununu ortadan kaldırmak için çağrılmıştır. WSDATA fonksiyonunun bilgileri wsData değişkenine aktarılmış, bu değişken ise "WSDATA"nın başlatılıp başlatılmadığının bilgisini tutar. "WORD" fonksiyonunun bilgileri ver değişkenine aktarılarak hangi versiyonun kullanılacağı bilgisi tutulur. Daha sonra int değişken tanımlanarak "WSAStartup" fonksiyonu ile versiyon ve veri adres bilgisi verilerek Winsock başlatılır. Başlatıldığında 0 değeri döner; eğer sistem 0 değerini döndürmezse Winsock'un başlatılamadığı söz konusu olacaktır.
Yukarıdaki kodda, listening adında bir soket oluşturduk. AF_INET, IPv4'ü temsil etmektedir. SOCK_STREAM ise TCP bağlantısını belirtir ve 0 parametresi ile TCP bayrağı verilmiştir. Yani, bu bir TCP bağlantısıdır. Eğer INVALID_SOCKET bildirimi dönerse, bu demektir ki soket oluşturulamadı ve bu durumda WSACleanup fonksiyonu ile Winsock işlemleri kapatılır.
Daha sonra, sockaddr_in yapısında sunucu adreslerini tutan hint adında bir değişken tanımladık. Alt parametrelerde görüldüğü üzere, IP tipi ve hangi port üzerinden sunucumuzu açmak istiyorsak o port numarasını belirtiyoruz. Ayrıca, gelen tüm IP bağlantılarını kabul etmesini istiyoruz; bu, sadece tek bir IP adresinden bağlantı sağlanmasını isteyen bir özelleştirme seçeneğidir.
Bu işlemden sonra, bind fonksiyonu önemli işlemler içerir. bind fonksiyonu, oluşturulan listening soketini hint değişkeninde bulunan IP ve porta bağlar. Bunu şöyle düşünebilirsiniz: evimizdeki Ethernet kablosunu modeme takıyoruz. Parametrelere gelecek olursak, öncelikle bağlanacak soket ismini verdik; bunu listening olarak adlandırmıştık. Daha sonra (sockaddr*)&hint parametresi çok önemlidir. hint değişkenindeki sunucu adres bilgilerini sockaddr formatına çevirir, çünkü bind fonksiyonu sockaddr formatında çalışmaktadır. Yan taraftaki sizeof(hint) parametresi ise sockaddr_in yapısının boyutunu belirlemektedir. Bu sayede dönüşümde ona göre alan açılır. Biraz karışık geldiğinin farkındayım; işte aşağıdaki resmi inceleyerek ikisi arasındaki farkı anlayabilirsiniz. listen fonksiyonu sayesinde ise aktif olarak iki cliente izin vereceğimizi belirttik.
Peki buraya kadar her şey güzel. Server bilgilerimiz hazır. Bu server bilgilerimizi serverimizi başlattığımızda görüntülemek istiyoruz bakalım gerçekten ip adresimiz ve verdiğimiz porttan yayın başlıyor mu ? Bunun için soketin bağlı olduğu IP adresi ve port numarasını almamız gerekmektedir.
Yukarıdaki kodda, sockaddr_in türünde bir local_addres değişkenine sunucu adres bilgilerini tutan parametreleri atadık, yani bir obje oluşturduk. Daha sonra, bunun bellekte kapladığı alanı tutacak bir local_adres_size int değişkeni tanımladık ve sizeof fonksiyonu ile local_addres değişkeninin boyutunu belirledik. Adından da anlaşılacağı üzere, getsockname() fonksiyonu bize sunucunun IP adresi bilgisini verecek. Şimdi gelelim içeriklerine: listening adında bir soket tanımlamıştık; oradan gelen IP ve port bilgileri local_addres değişkeninin içerisine yazılır. Daha sonra, getsockname fonksiyonunun anlaması için sockaddr formatına dönüştürülür. Son olarak, parametre olarak oluşturmuş olduğumuz local_adres_size değişkeninin adresini yazıyoruz, çünkü local_addres değişkeninin içerisindeki veri kadar bellekte yer ayıracaktır. Biraz karışık olduğunun farkındayım; fakat alıştıkça basitleşmeye başlayacaktır.
Şimdi bilgilerimiz local_addres değişkeninde tutulmaktadır. INET_ADDRSTRLEN sabiti, IP adresini string olarak saklamak için gereken bellek boyutunu belirler. Bunu şu şekilde düşünebilirsiniz: char ip_str[15] yerine, IP adresi string bilgisi kaç byte ise o kadar yazılır; bu işlem en güvenilir yöntemdir.
inet_ntop() fonksiyonu ise IP adresini okunabilir bir formata dönüştürmek için kullanılır. Öncelikle IP adres tipini AF_INET (IPv4) olarak belirtiyoruz. &local_addres.sin_addr parametresi, IP adresinin bulunduğu sockaddr_in yapısındaki sin_addr üyesinin adresini belirttik. Bunun string halini ip_str değişkenine yazdıracağımızı belirttik. Yani git oradaki ip adresini al ip_str değişkenine string olarak yaz dedik. En son ise belirtilen bellek kadar yer ayırmaktadır. İlk başta belirttiğimiz AF_INET, yani IPv4 tipini bu yüzden veriyoruz.
Ekrana bilgileri bastırırken, port bölümünde ntohs fonksiyonu içerisindeki hint.sin_port parametresi sayesinde sunucunun dinlediği port numarası çekilir ve ntohs sayesinde host byte olarak dönüştürülür. IP bölümünde ise zaten ip_str içerisinde IP adresimizin string hali mevcuttu; onu sadece ekrana yazdırmış olduk.
Şimdi ise bağlantıları sürekli dinleyeceğimiz bir soket yapalım ve iki kişinin max girebileceği bir client kontrol sistemi yazalım.
Yukarıdaki resimlerde görüldüğü üzere, const int değişkeni tanımladık ve 2 değerini verdik. Bağlanacak olan istemcilerin depolanması için vector (taşıyıcı) parametresinden yararlanarak maksimum 2 istemci girmesini sağlayacağız. Şimdi while döngümüze gelelim. Öncelikle gelen bağlantıları kabul etmek için bir soket oluşturmamız gerekiyor. sockaddr_in fonksiyonuna gelen bilgileri client'e atılmasını belirttik. Daha sonra bu adres bilgilerin boyutları tekrar bağlantı için bize lazım olacağından ötürü sizeof() fonksiyonu ile bellekteki boyutunu aldık. ClientSocket adında bağlantı için soket oluşturduk. accept fonksiyonu ile bağlantıları kabul edeceğiz. Bağlantıları kabul edeceğimiz listening soketini kullandık; bunun sebebi, listening soketinde IP ve port bilgilerimiz tutuluyordu. Bu bilgiler (sockaddr*)&client parametresi ile client'in içerisine yazılır ve sockaddr formatına dönüştürülür. En son parametre ise boyutunun adres bilgisidir.
Şimdi buraya kadar ne yaptık onu tartışmak gerekirse; Bir sunucu yayını başlatmak için server bilgilerimizi girdik. Bu server bilgilerimizin ekrana çıktı vermesini sağladık. Serverimize bağlanacak max client sayımızı belirttik. Şimdi dilerseniz bir serverimizi başlatalım. CMD yi açıp cpp dosyamın, dosya konumuna gidip g++ -m32 -o server.exe server.cpp -lws2_32 komutumu yazıyorum.
Görüldüğü üzere serverimiz gayet başarılı şekilde çalışıyor. Şimdi ise clientimizi yazalım ve bu clientimizi serveremize bağlayalım.
Öncelikle server dosyamızda olduğu gibi winsock kütüphanemizi aktif ediyoruz bu bizim socket işlemlerimizi gerçekleştirmemiz için yani network işlemlerimizi gerçekleştirmemiz için gerekli kütüphanemiz. Daha sonra TCP/IP bağlantısı için soket oluşturuyoruz.
Burada inet_pton() fonksiyonu verilen IP adresini ikili formata dönüştürür ve bu adresi hint değişkenindeki sin_addr üyesine yazar. Bu yapı, connect fonksiyonu tarafından kullanılarak sunucuya bağlanmak için gereken IP adresini içerir.
Şimdi cmd ile g++ -m32 -o client.exe client.cpp -lws2_32 komutunu girerek exeye çevirelim. Sunucumuzu çalıştırıp servere bağlanmaya çalışalım.
Görüldüğü üzere clientimi çalıştırdığımda sağlıklı bir şekilde servere giriş işlemi sağlandı. Şimdi bu servere bağlantı için bir kullanıcı adı ve şifre isteyen giriş yapalım
Mantık şu şekilde olacak. Client servere bağlanmak istediğinde server tarafından kullanıcı adı ve şifre isteği gönderilecek. Tekrar server dosyama geliyorum.
Kullanıcı adı ve şifreyi al bölümlerinde buf 4096 byte karşıdan veri alır ve buf değişkeninde saklar. 0 parametresi ile bufun başına git bilgi -1 ile gelen verinin tamamının bir eksiğini al yani enter yapıldığı için onu alma demiş oluyoruz.
Sunucuya ait giriş bilgileri bilgi.txt dosyasında tutmak istedim bu nedenle kullaniciadi:sifre şeklinde yazdım görmüş olduğunuz kodda : öncesi kullanıcı adı : sonrası şifre olacak şekilde kodladım.
En son olarak main fonksiyonumun içerisine tekrar geliyorum ve bilgiler fonkisyonuma clientSocket parametremi gönderiyorum. clientSocket benim bağlantılar için kullandığım yani SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize); olarak kullandığım soketimdi. Bilgiler fonksiyonu bir bool fonksiyon bana ya true dönecek yada false eğer true dönerse bilgiler fonksiyonunda belirttiğimiz üzere bilgiler doğru ise true dönmekte. Yanlış ise false dönmekte. True dönerse daha önce oluşturmuş olduğumuz vectorun içerisine clientimizi atarak servere dahil etmekte aksi halde soketi kesmekte. Şimdi clientimizi kodlayalım.
Clientimizde ise sürekli olarak mesajlarını dinleyen bir sistem yazmamız lazım çünkü server tarafından bize kullanıcı adı ve şifre sorulacak.
Buradada mantık aynı değişen bir şey yok. Yine bilgi alımı gerçekleşiyor tek fark bunu süreklilik haline getirilmesi. Şimdi main fonksiyonumuza inerek bu receiveMesaages fonksiyonumuzu aktif edelim.
Ben burada ayrı iş parçacığı olarak sürekli çalışması açısından thread fonksiyonunu kullandım paralel olarak diğer fonksiyonlar ile aynı anda çalışması açısından bana kolaylık sağlamakta siz kendiniz direkt olarakda çalıştırabilirsiniz şimdi server ve clientimizi tekrar compiler edelim ve çalıştıralım.
Evet işlem başarılı artık servere giriş yaptık. Şimdi gerçekçi olması açısından uzak masaüstüm ile linux sunucuma bağlanacağım ve oradan ngrok yardımı ile bir yayın başlatacağım ngrokun sunmuş olduğu tünelleme ile serverimizi oradan başlatıp windows pcden clienti çalıştırıp bağlanmayı deneyeceğim. Fakat linux için server kodlarında ufak değişiklikler olmakta winsock kütüphanesi windowsa özel olduğundan ötürü bazı kütüphanelerde değişiklik olacağı söz konusu oraları atlayacağım.
ngrok üzerinden 9595 portunu açtım. Bana global olarak kullanabileceğim portu 19439 vermiş. Şimdi ngroku pingleyelim ip adresini alalım.
evet bu ip adresini windows pcmize gidip clientimize bağlantı için tekrar ayarlamamızı yapalım ondan önce serverimizi başlatalım.
Şimdi bağlanmayı deneyelim.
Evet clientimizi açtık ve linux sunucumuzda bildirim düştü buda bağlandığımızı gösterir. İşte metin2, knight online gibi oyunlarda Sunucu bağlantıları bu şekilde kurulmaktadır. Bu konunda sonuna geldik. Başka bir konuda görüşmek üzere.
Dilerseniz Kodlara geçelim. Bu aşamalar C++ dili ile yazılmış olup, iostream, string, thread, vector, algorithm, winsock2.h, ws2tcpip.h, fstream, clocale kütüphanelerinden yararlanılmıştır.
Öncelikle yukarıda görmüş olduğumuz kod bloğunda yorum satırları mevcut, fakat ben detaylıca açıklamasını yapacağım. Winsock (Windows Sockets) kütüphanesi, bize Windows işletim sistemi üzerinde ağ olaylarını yönetebilmemize olanak tanımaktadır. Soket oluşturma "socket()", bağlantı kurma ve dinleme "bind(), listen(), accept()", veri gönderme ve alma "send(), recv()", bağlantı kapatma "closesocket()" gibi daha birçok fonksiyon ve işlevsellik tanımaktadır.
Şimdi gelelim kodlarımıza. "setlocale" fonksiyonu, Türkçe karakter sorununu ortadan kaldırmak için çağrılmıştır. WSDATA fonksiyonunun bilgileri wsData değişkenine aktarılmış, bu değişken ise "WSDATA"nın başlatılıp başlatılmadığının bilgisini tutar. "WORD" fonksiyonunun bilgileri ver değişkenine aktarılarak hangi versiyonun kullanılacağı bilgisi tutulur. Daha sonra int değişken tanımlanarak "WSAStartup" fonksiyonu ile versiyon ve veri adres bilgisi verilerek Winsock başlatılır. Başlatıldığında 0 değeri döner; eğer sistem 0 değerini döndürmezse Winsock'un başlatılamadığı söz konusu olacaktır.
Yukarıdaki kodda, listening adında bir soket oluşturduk. AF_INET, IPv4'ü temsil etmektedir. SOCK_STREAM ise TCP bağlantısını belirtir ve 0 parametresi ile TCP bayrağı verilmiştir. Yani, bu bir TCP bağlantısıdır. Eğer INVALID_SOCKET bildirimi dönerse, bu demektir ki soket oluşturulamadı ve bu durumda WSACleanup fonksiyonu ile Winsock işlemleri kapatılır.
Daha sonra, sockaddr_in yapısında sunucu adreslerini tutan hint adında bir değişken tanımladık. Alt parametrelerde görüldüğü üzere, IP tipi ve hangi port üzerinden sunucumuzu açmak istiyorsak o port numarasını belirtiyoruz. Ayrıca, gelen tüm IP bağlantılarını kabul etmesini istiyoruz; bu, sadece tek bir IP adresinden bağlantı sağlanmasını isteyen bir özelleştirme seçeneğidir.
Bu işlemden sonra, bind fonksiyonu önemli işlemler içerir. bind fonksiyonu, oluşturulan listening soketini hint değişkeninde bulunan IP ve porta bağlar. Bunu şöyle düşünebilirsiniz: evimizdeki Ethernet kablosunu modeme takıyoruz. Parametrelere gelecek olursak, öncelikle bağlanacak soket ismini verdik; bunu listening olarak adlandırmıştık. Daha sonra (sockaddr*)&hint parametresi çok önemlidir. hint değişkenindeki sunucu adres bilgilerini sockaddr formatına çevirir, çünkü bind fonksiyonu sockaddr formatında çalışmaktadır. Yan taraftaki sizeof(hint) parametresi ise sockaddr_in yapısının boyutunu belirlemektedir. Bu sayede dönüşümde ona göre alan açılır. Biraz karışık geldiğinin farkındayım; işte aşağıdaki resmi inceleyerek ikisi arasındaki farkı anlayabilirsiniz. listen fonksiyonu sayesinde ise aktif olarak iki cliente izin vereceğimizi belirttik.
Peki buraya kadar her şey güzel. Server bilgilerimiz hazır. Bu server bilgilerimizi serverimizi başlattığımızda görüntülemek istiyoruz bakalım gerçekten ip adresimiz ve verdiğimiz porttan yayın başlıyor mu ? Bunun için soketin bağlı olduğu IP adresi ve port numarasını almamız gerekmektedir.
Yukarıdaki kodda, sockaddr_in türünde bir local_addres değişkenine sunucu adres bilgilerini tutan parametreleri atadık, yani bir obje oluşturduk. Daha sonra, bunun bellekte kapladığı alanı tutacak bir local_adres_size int değişkeni tanımladık ve sizeof fonksiyonu ile local_addres değişkeninin boyutunu belirledik. Adından da anlaşılacağı üzere, getsockname() fonksiyonu bize sunucunun IP adresi bilgisini verecek. Şimdi gelelim içeriklerine: listening adında bir soket tanımlamıştık; oradan gelen IP ve port bilgileri local_addres değişkeninin içerisine yazılır. Daha sonra, getsockname fonksiyonunun anlaması için sockaddr formatına dönüştürülür. Son olarak, parametre olarak oluşturmuş olduğumuz local_adres_size değişkeninin adresini yazıyoruz, çünkü local_addres değişkeninin içerisindeki veri kadar bellekte yer ayıracaktır. Biraz karışık olduğunun farkındayım; fakat alıştıkça basitleşmeye başlayacaktır.
Şimdi bilgilerimiz local_addres değişkeninde tutulmaktadır. INET_ADDRSTRLEN sabiti, IP adresini string olarak saklamak için gereken bellek boyutunu belirler. Bunu şu şekilde düşünebilirsiniz: char ip_str[15] yerine, IP adresi string bilgisi kaç byte ise o kadar yazılır; bu işlem en güvenilir yöntemdir.
inet_ntop() fonksiyonu ise IP adresini okunabilir bir formata dönüştürmek için kullanılır. Öncelikle IP adres tipini AF_INET (IPv4) olarak belirtiyoruz. &local_addres.sin_addr parametresi, IP adresinin bulunduğu sockaddr_in yapısındaki sin_addr üyesinin adresini belirttik. Bunun string halini ip_str değişkenine yazdıracağımızı belirttik. Yani git oradaki ip adresini al ip_str değişkenine string olarak yaz dedik. En son ise belirtilen bellek kadar yer ayırmaktadır. İlk başta belirttiğimiz AF_INET, yani IPv4 tipini bu yüzden veriyoruz.
Ekrana bilgileri bastırırken, port bölümünde ntohs fonksiyonu içerisindeki hint.sin_port parametresi sayesinde sunucunun dinlediği port numarası çekilir ve ntohs sayesinde host byte olarak dönüştürülür. IP bölümünde ise zaten ip_str içerisinde IP adresimizin string hali mevcuttu; onu sadece ekrana yazdırmış olduk.
Şimdi ise bağlantıları sürekli dinleyeceğimiz bir soket yapalım ve iki kişinin max girebileceği bir client kontrol sistemi yazalım.
Yukarıdaki resimlerde görüldüğü üzere, const int değişkeni tanımladık ve 2 değerini verdik. Bağlanacak olan istemcilerin depolanması için vector (taşıyıcı) parametresinden yararlanarak maksimum 2 istemci girmesini sağlayacağız. Şimdi while döngümüze gelelim. Öncelikle gelen bağlantıları kabul etmek için bir soket oluşturmamız gerekiyor. sockaddr_in fonksiyonuna gelen bilgileri client'e atılmasını belirttik. Daha sonra bu adres bilgilerin boyutları tekrar bağlantı için bize lazım olacağından ötürü sizeof() fonksiyonu ile bellekteki boyutunu aldık. ClientSocket adında bağlantı için soket oluşturduk. accept fonksiyonu ile bağlantıları kabul edeceğiz. Bağlantıları kabul edeceğimiz listening soketini kullandık; bunun sebebi, listening soketinde IP ve port bilgilerimiz tutuluyordu. Bu bilgiler (sockaddr*)&client parametresi ile client'in içerisine yazılır ve sockaddr formatına dönüştürülür. En son parametre ise boyutunun adres bilgisidir.
Şimdi buraya kadar ne yaptık onu tartışmak gerekirse; Bir sunucu yayını başlatmak için server bilgilerimizi girdik. Bu server bilgilerimizin ekrana çıktı vermesini sağladık. Serverimize bağlanacak max client sayımızı belirttik. Şimdi dilerseniz bir serverimizi başlatalım. CMD yi açıp cpp dosyamın, dosya konumuna gidip g++ -m32 -o server.exe server.cpp -lws2_32 komutumu yazıyorum.
Görüldüğü üzere serverimiz gayet başarılı şekilde çalışıyor. Şimdi ise clientimizi yazalım ve bu clientimizi serveremize bağlayalım.
Öncelikle server dosyamızda olduğu gibi winsock kütüphanemizi aktif ediyoruz bu bizim socket işlemlerimizi gerçekleştirmemiz için yani network işlemlerimizi gerçekleştirmemiz için gerekli kütüphanemiz. Daha sonra TCP/IP bağlantısı için soket oluşturuyoruz.
Burada inet_pton() fonksiyonu verilen IP adresini ikili formata dönüştürür ve bu adresi hint değişkenindeki sin_addr üyesine yazar. Bu yapı, connect fonksiyonu tarafından kullanılarak sunucuya bağlanmak için gereken IP adresini içerir.
Şimdi cmd ile g++ -m32 -o client.exe client.cpp -lws2_32 komutunu girerek exeye çevirelim. Sunucumuzu çalıştırıp servere bağlanmaya çalışalım.
Görüldüğü üzere clientimi çalıştırdığımda sağlıklı bir şekilde servere giriş işlemi sağlandı. Şimdi bu servere bağlantı için bir kullanıcı adı ve şifre isteyen giriş yapalım
Mantık şu şekilde olacak. Client servere bağlanmak istediğinde server tarafından kullanıcı adı ve şifre isteği gönderilecek. Tekrar server dosyama geliyorum.
Kullanıcı adı ve şifreyi al bölümlerinde buf 4096 byte karşıdan veri alır ve buf değişkeninde saklar. 0 parametresi ile bufun başına git bilgi -1 ile gelen verinin tamamının bir eksiğini al yani enter yapıldığı için onu alma demiş oluyoruz.
Sunucuya ait giriş bilgileri bilgi.txt dosyasında tutmak istedim bu nedenle kullaniciadi:sifre şeklinde yazdım görmüş olduğunuz kodda : öncesi kullanıcı adı : sonrası şifre olacak şekilde kodladım.
En son olarak main fonksiyonumun içerisine tekrar geliyorum ve bilgiler fonkisyonuma clientSocket parametremi gönderiyorum. clientSocket benim bağlantılar için kullandığım yani SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize); olarak kullandığım soketimdi. Bilgiler fonksiyonu bir bool fonksiyon bana ya true dönecek yada false eğer true dönerse bilgiler fonksiyonunda belirttiğimiz üzere bilgiler doğru ise true dönmekte. Yanlış ise false dönmekte. True dönerse daha önce oluşturmuş olduğumuz vectorun içerisine clientimizi atarak servere dahil etmekte aksi halde soketi kesmekte. Şimdi clientimizi kodlayalım.
Clientimizde ise sürekli olarak mesajlarını dinleyen bir sistem yazmamız lazım çünkü server tarafından bize kullanıcı adı ve şifre sorulacak.
Buradada mantık aynı değişen bir şey yok. Yine bilgi alımı gerçekleşiyor tek fark bunu süreklilik haline getirilmesi. Şimdi main fonksiyonumuza inerek bu receiveMesaages fonksiyonumuzu aktif edelim.
Ben burada ayrı iş parçacığı olarak sürekli çalışması açısından thread fonksiyonunu kullandım paralel olarak diğer fonksiyonlar ile aynı anda çalışması açısından bana kolaylık sağlamakta siz kendiniz direkt olarakda çalıştırabilirsiniz şimdi server ve clientimizi tekrar compiler edelim ve çalıştıralım.
Evet işlem başarılı artık servere giriş yaptık. Şimdi gerçekçi olması açısından uzak masaüstüm ile linux sunucuma bağlanacağım ve oradan ngrok yardımı ile bir yayın başlatacağım ngrokun sunmuş olduğu tünelleme ile serverimizi oradan başlatıp windows pcden clienti çalıştırıp bağlanmayı deneyeceğim. Fakat linux için server kodlarında ufak değişiklikler olmakta winsock kütüphanesi windowsa özel olduğundan ötürü bazı kütüphanelerde değişiklik olacağı söz konusu oraları atlayacağım.
ngrok üzerinden 9595 portunu açtım. Bana global olarak kullanabileceğim portu 19439 vermiş. Şimdi ngroku pingleyelim ip adresini alalım.
evet bu ip adresini windows pcmize gidip clientimize bağlantı için tekrar ayarlamamızı yapalım ondan önce serverimizi başlatalım.
Şimdi bağlanmayı deneyelim.
Evet clientimizi açtık ve linux sunucumuzda bildirim düştü buda bağlandığımızı gösterir. İşte metin2, knight online gibi oyunlarda Sunucu bağlantıları bu şekilde kurulmaktadır. Bu konunda sonuna geldik. Başka bir konuda görüşmek üzere.


