Modüller | socket

socket modülü ile bir sunucu (server) veya bir istemci (client) kodlayabiliyor ve bir ağ oluşturabiliyoruz. Her şeyden önce eğer Network konusuna hâkim değilseniz aşağıda linklerini verdiğim blogları kesinlikle okumalısınız. Burada kodlamadan ziyade bilgi konuşacaktır. Bu yüzden socket modülünü kullanabilmeniz için mantığı kavramak zorundasınız. Ayrıca aşağıdaki bloglarda bulunan şemaları iyice incelemeniz, açıklamalarını da dikkatli bir şekilde okumanız gerekiyor.

IP (Internet Protocol)

OSI Katmanları

TCP/IP

UDP

LAN - VLAN - WAN - WLAN

Ağ Cihazları

Server

"Socket" kelimesinin karşılığı 'soket' ya da 'port' şeklindedir. Buradaki port mantığından, önceki bloglarda çokça bahsettim ama ufak bir özet geçelim. Port dediğimiz şey, erişmek istediğimiz yapıya açılan kapılardır. Örneğin evinize girebilmeniz için ilk önce bir anahtara sahip olmalı ve o anahtar ile dış kapıyı açıp içeri girmelisiniz. Buradaki port mantığı da tamamen bu şekildedir. Eğer bir sunucuya erişecekseniz ilk önce onun Port'una erişmeniz gerekir.

İlk önce Local IP adresimizi bulmamız gerekiyor. Bunu Windows üzerinde cmd terminal ekranına 'ipconfig' komutunu verip bulabilirsiniz.

Şimdi, iki adet Python dosyası oluşturmam lazım. Bunlardan biri server.py olacak, diğeri ise client.py olacak. Bunları oluşturduktan sonra server.py sayfasına geçip import socket dedikten sonra IP adresimizi tanımlamamız gerekiyor.

Bunu, HOST = "" şeklinde tanımlıyorum. Büyük harflerle yazmamın sebebi ise bunun genel kabul gören şeklinin bu olmasıdır. Tırnak işaretleri arasına kendi IP adresinizi yazmanız gerekiyor.

EK BİLGİ

Eğer IP adresinizi bulmakta zorluk yaşıyorsanız ya da daha esnek bir yapı oluşturmak istiyorsanız socket modülü ile IP adresinizi dinamik olarak çekebilirsiniz:

IP adresi sorununu çözdükten sonra bir adet PORT numarası belirtmemiz gerekiyor. Server ve client, belirteceğimiz bu numara sayesinde iletişime geçeceklerdir. Bu noktada isterseniz 8080 (HTTP) portunu kullanabilirsiniz ya da örneğin 4444 de yazabilirsiniz; size kalmış. Ben 4444 yazmak istiyorum.

Şimdi, socket ile bir server objesi tanımlamamız gerekiyor. Bunun için server isimli bir değişken atıyorum ve karşısına socket.socket() diyorum. Yani yapımız, aşağıdaki gibi görünmelidir.

Peki, şimdi server isimli bir objemiz oldu. Ancak madem bir server-client yapısı oluşturuyoruz. O zaman bizim, bu iki yapı arasında kurulacak iletişimin nasıl olacağını da belirlememiz gerekir.

Bunun için oluşturduğum objede yer alan parantezler arasına giriyorum ve socket. diyorum.

Bu noktada, iletişimin nasıl olacağına karar vermeniz gerekiyor. Biz, AF_INET seçeneğini seçeceğiz. AF_INET, IPv4 adresleri ile iletişim kurmamıza olanak tanıyacaktır. AF_INET6 seçeneği ise IPv6 adreslerini ifade eder. Biraz önce HOST = "192.168.1.179" şeklinde bir tanımlama yaptım ve oradaki adres benim IPv4 adresim. Dolayısıyla AF_INET seçeneğini seçiyorum.

Şimdi, iletişimin TCP ile mi yoksa UDP ile mi olacağını belirlememiz lazım. Amacımız, server ile client arasında güvenli bir iletişim kurmak olduğu için TCP protokolünü tercih edeceğiz. Bunun için;

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ifadesini kuruyorum.

Eğer iletişimin UDP ile sağlanmasını istiyorsanız socket.SOCK_DGRAM ifadesini vermeniz gerekir:

İletişim türümüzü belirledikten sonra server ile client yapılarının bağlanabilmesi için bind() fonksiyonunu kullanıyorum ve içerisine, HOST ve PORT bilgilerini veriyorum. Bu sayede HOST'a oradaki açık kapı (PORT) ile bağlanacağız. Ancak bu bilgileri ek bir paranteze vermemiz lazım. Yani bind(()) şeklinde bir kullanım söz konusu.

Bağlantıyı da sağladıktan sonra bağlantıdan akacak olanları dinlememiz gerekiyor. Bunun için listen() fonksiyonunu kullanıyorum.

Şimdi, paketlerin sürekli olarak akması için, bir kesinti olmaması için sonsuz bir döngü açıyorum. Bunu while True: ile yapacağım.

Az önce bağlanma ve dinleme işini gerçekleştirdik. Bu döngü içerisinde bir de 'kabul etme' işlemini yapmamız lazım. Çünkü TCP'de biliyorsunuz ki bir kabul etme işlemi söz konusu.

Bu noktada accept() yani kabul etme fonksiyonu, iki parametre alıyor. Bunlardan biri istemciyle sağlanan iletişim (istemcinin kendisi), diğeri de istemcinin adresi. O yüzden communication, address ifadelerini verdim ki bu yapı, neyi kabul ettiğini ve neyle iletişime geçeceğini bilsin. Yani accept() fonksiyonu burada, istemciyi ve istemcinin adresini kabul etmekle görevli. Bunun için iki parametreyi de server.accept() ifadesine eşitledim. 

Bu 'kabul etme' durumu gerçekleştiğinde bağlantı tamamen sağlanmıştır. Bu yüzden oraya "bağlanıldı" tarzında bir mesaj gönderiyorum. Hemen sonrasında bir hoş geldin mesajı da verebiliriz.

"Bağlanıldı" mesajı, kendimiz yani server için gösterilecektir. Ancak communication.send() ifadesi ile, client ekranında gözükecek mesajı veriyoruz. Bu noktada daha önce görmediğimiz 'bytes' veri tipini kullanıyoruz ve encode('utf-8') diyoruz. OSI Katmanlarından bileceğiniz üzere veriyi byte tipinde encode ederek yolluyoruz. encode() içerisine, yazı dönüştürücü türü veriyorum. İsterseniz 'ascii' vesaire de kullanabilirsiniz. Ancak utf-8 sık kullanılanlardandır.

Dediğim gibi, send ile yolladığımız mesaj, client ekranına düşecektir.

Şimdi, bağlantı sonrasında bağlantının sağlıklı bir şekilde kurulup kurulmadığıyla alakalı bir karşılama mesajı hazırlamamız lazım. Yani biz kullanıcıyla iletişime geçtiğimizde ona hoş geldin diyoruz ama kullanıcı da bizimle iletişime geçtiğinde bunu bilmemiz lazım. O yüzden kullanıcı bizimle iletişim kurduğunda bu sefer server ekranında gözükecek mesajı hazırlıyoruz.

19. satırda bunu yaptık. message değişkeni içerisinde biraz önce tanımladığımız communication değişkenini karşıladık ve bunu, recv() fonksiyonuyla yaptık. recv(), "receive" kelimesinden gelir ve anlamı "karşılamak, almak" şeklindedir. client iletişim kurduğunda bu iletişimi alıyor, karşılıyor olmamız lazım. recv() içerisine verdiğimiz 1024 sayısı, kaç byte olduğunu ifade eder. 1024 byte'lık bir mesaj yolladık.

Hemen sonrasında decode ettiğimizi görüyorsunuz. Bu, birazdan kodlayacağımız client.py dosyasında bize encode edilerek gönderilen mesajlar içindir. Onları decode edip utf-8 formatında görüntüleyeceğiz. Zaten hemen altında bunu ekrana yazdırıyoruz.

Request-Response işlemleri bittikten sonra bu iletişimi kapatmamız gerekir. Dolayısıyla 22. satırda gördüğünüz üzere communication.close() diyerek kapatma işlemini de gerçekleştiriyorum ve bunu ekrana yazdırıyorum.

Oradaki break ifadesi iletişimin sonlanması için değil, döngünün sonlanması içindir.

Şimdi, client.py dosyasına gidelim ve import socket dedikten sonra HOST ve PORT bilgilerimizi koyalım. Bunlar iletişim için önemli ve gerekli.

Ayrıca yine iletişim türünü belirlememiz gerekiyor ki birbirlerini görsünler. Hemen sonrasında connect() fonksiyonu ile bu bağlantıyı sağlıyorum. Bu, server.py'deki bind() gibidir.

Sonrasında yine send() fonksiyonunu kullanarak server'a bağlandığımızda server üzerinde görülecek mesajı veriyoruz. Bir nevi kendimizi server'a tanıtıyoruz. Bunu encode ederek yolluyoruz; server.py'deki decode işlemi ile birbirlerini tamamlayacaklardır. Burada send() fonksiyonuyla beraber bytes() veri tipini kullanmadım çünkü onsuz da olabileceğini görün istedim. Ancak siz yine de kullanmaya özen gösterin.

15. satırdaki kod ise server üzerinden gelen mesajı decode ederek karşılamaya yarıyor.

Şimdi, 2 adet terminal açıyorum ve birinde server.py dosyasını, diğerinde client.py dosyasını çalıştırıyorum. Ancak ilk önce server.py çalışmalı.

server.py tarafında "... kullanıcısına bağlanıldı" diye bir ifade çıktı. Sonrasında server.py tarafında "İstemci: Selam, Ben Cyber Worm" şeklinde bir ifade çıktı. Bu, client.py içerisinde send() fonksiyonuyla yolladığımız mesajdır.

Sonrasında client.py ekranında "Hoş geldin Cyber Worm" yazısı gözüktü. Bu, server.py dosyasında kodladığımız send() fonksiyonu sayesinde oldu; ilk önce encode olarak yollandı, sonra decode olarak gösterildi.

Bu işlemler bittikten sonra da "... ile olan bağlantı sonlandı" şeklinde bir mesaj geldi ve kurduğumuz bu küçük Network başarıyla çalıştı.

Bu yazıda socket modülünü bir örnekle anlatmaya çalıştım. Bu yazı boyunca send(), recv(), bytes, encode(), decode() gibi birçok şeyi öğrendiniz. Yukarıdaki örnekte gerçekleşen işlemler bir saniyeden daha kısa sürede gerçekleşmiştir. Dolayısıyla ne olduğunu anlamanız açısından yukarıda yazdığım sıraya göre okumanız, yorumlamanız gerekir. Bu kodu daha da güzelleştirmek sizin elinizdedir; belki biz de ufak bir mesajlaşma programı yapabiliriz. Sevgiler.


Yayınlanma Tarihi: 2022-11-30 12:37:39

Son Düzenleme Tarihi: 2022-12-04 13:40:20