Python Socket Programming - 1

Kendim için hazırladığım bu not oldukça uzun sürecek. Load Balancing konusuna çalışırken kendimi bir orada bir burada derken en sonunda Socket konusu içinde buldum. Tabii bu oldukça geniş bir konu olmasına rağmen kendim için alacağım kısa notların ilerde faydası olacağını düşünüyorum. Bu tarz teknik konularda çok fazla teorik hatam olabilir.

Bir sistemde iki process arası communicate işlemi için pipes, shared memory gibi birçok teknik kullanılır fakat aynı sistemden farklı olarak network üzerinde iki process arasında communication kurabilmek için Socket tekniği kullanılır. Bu kullanım şu tanımı ortaya çıkarmaktadır; “Socket aynı network üzerindeki iki sistem arasındaki iletişimin uç noktasıdır.” Tanımdan anlaşılacağı üzere network üzerinde iki sistemin etkileşime girebilmesi için socketlere ihtiyaç vardır. Socketler IP adresleri ve portların kombinasyonu olarak tanımlanırsa, local socket ve remote sistemdeki socket’in kombinasyonu da 4-tuple olarak tanımlanır. Kısa bir tanımn ardından, Socket programlama için bir Client ve Server’a ihtiyacımız var.

Python zaten built-in socket modülü sağlamaktadır. Bu yazıda da sık referans olarak başvuracağım Python’ın belgeleri için tıklayabilirsiniz. Ilk olarak Server tarafını ele alalım. Server tarafı gelen bağlantıları dinleyeceğinden dolayı bu taraf “listening socket” olarak tanımlanır. Basit bir Server tarafı için:

import socket

HOST = "127.0.0.1"
PORT = 45645

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    print("%s is IP and %s is PORT now listening." % (HOST, PORT))
    conn, addr = s.accept()
    with conn:
        print(f'Connected by {addr}')
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)

Kodun ilk kısmında Python’ın socket modülünü import ettik. Daha sonra Socketin dinleyeceği (listen) HOST ve PORT’u belirledik. Port 0-65535 arasinda bir int deger olmalidir. socket.socket() ile bir socket objesi yarattık ve bunu with statement’ı ile kullanmaya başladık. Kodun devamına geçmenden önce socket()’in alabileceği parametreleri ve gönderdiğimiz argümanları inceleyelim. Bir socket objesi oluşturuken kullanılan syntax bu şekildedir:

class socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)

Anlaşılacağı üzere dört farklı parametre almaktadır ve bunların Constants yani sabitleri bulunmaktadır. Birinci argümanın sabitleri address ve protocol family olarak tanımlanır. Sisteme bağlı olarak değişse de genel olarak üç farklı sabit vardır: 

socket.AF_UNIX
socket.AF_INET
socket.AF_INET6

Ikınci argüman olarak alınan sabitler ise socketin Type’ını temsil etmektedir. Sisteme göre değişse de en sık kullanılan sabitler şunlardır:

socket.SOCK_STREAM
socket.SOCK_DGRAM
socket.SOCK_RAW
socket.SOCK_RDM
socket.SOCK_SEQPACKET

Üçüncü argüman protocol number için ise en sık kullanılan ve default değer 0’dır. Son olarak dördüncü argüman olan fileno belirtilirse, family, type ve proto değerleri belirtilen değere göre otomatik olarak algılanır.

Server tarafı için oluşturduğumuz socket objesi için en sık kullanılan değerler tercih edildi. AF_INET (IPv4) ve SOCK_STREAM (TCP). Socket objemizi oluşturduktan sonra bu soketi bind() metodu ile belirli bir IP adresi ve porta bağladık. Bu metot, socket objesi oluşturulurken verilen address family değerine göre değişiklik göstermektedir.  Buradan detaylı inceleyebilirsiniz. Daha sonra listen() metodu ile artık bağlantıları kabul etmeye hazır olduğumuzu diğer bir ifade ile bağladığımız IP adresini ve portunu dinlemeye başladığımızı belirttik. accept() metodu ise Client tarafından gelen bağlantıyı kabul ederek, IP Family’e göre yeni bir socket objesi oluşturmaktır; conn ve addr değişkenleri ile socketin host ve port’unu tutuyoruz. Bu şekilde Server, Client ile iletişim kurabilmektedir. socket.recv(), Client ile iletişim kurduğumuz soketten gelen dataları alır. Ardından gelen datayı temsil edecek bir byte objesi döndürmektedir. Tek seferde alınacak data boyutu ise göndermiş olduğumuz ilk argüman buffsize(1024) ile belirlenir. Buffsize ‘ın alabileceği değerler kümesinin 2’nin kuvveti olması gerektiğini unutmayalım. En azından Python bize bu şekilde söylemektedir. 

    For best match with hardware and network realities, the value of bufsize should be a relatively small power of 2, for example, 4096.

socket.sendall() ile Client tarafından gelen datayı okuduktan sonra sockete byte data gönderme işlemini gerçekleştiriyoruz. Eğer Client tarafından gelen data boş ise with statement yardımı ile sockete otomatik olarak socket.close() işlemi uyguluyoruz. Eğer with statement’ı ile kullanmadıysak bunu manuel olarak yapmamız gerekmekte. Server tarafını oluşturduğumuza göre bir sonraki yazıda Client tarafını oluşturarak test edebiliriz.

 


İletişime geçmek, yorum bırakmak veya hatalarımı düzetlmek istersen mail atabilirsin.

iletişim için tıklama yeri