Python ile Socket Programlama 4

Merhabalar, One to One Chat(1’e 1 mesajlaşma) uygulamamızı AsyncIO kullanarak yeniden yapacağımızı söylemiştik gelin birlikte yapalim.

Yazımızda bir önceki AsyncIO socket örneğinden alıntılara yer vereceğim için AsyncIO ile Basit Socket Örneği yazımı okumanızı tavsiye ederim.

Python Socket 1’e 1 Mesajlaşma Örneği(AsyncIO ile)

Bir önceki yazımızda da bahsettiğimiz gibi

1’e 1 mesajlaşma yapabilmemiz için kullanıcının ve kullanıcının mesaj attığı kişinin servera bağlı olması gerekir. Bağlı olmasının yanında bu kişilerin socket bağlantılarının bir yerde depolamamamız gerekir.

Biz burada Basit bir şekilde 2 kullanıcının birbiri ile haberleşmesini sağlayacağız. Basit bir şekilde olacağından dolayı gerçek kullanımlar için bir çok kontrol yapısı eklenmesi gerekir.

Python ile Socket Programlama 3

Server.py dosyamızı yazarken AsyncIO kullanacağız.

Not: Bu örnekte string ve seperatorleri kullanarak haberleşmeyi sağladık. Daha iyi bir kullanım ve kontrol için json kullanabilirsiniz.

# server.py
import socket
import asyncio

HEADER = 64
IP = socket.gethostbyname(socket.gethostname())
PORT = 9999
ADDR = (IP, PORT)
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "DISCONNECT_SERVER_CODE"
USERNAME_MESSAGE = "EXAMPLE_APP_USERNAME_FIELD"
SEP = "///**//"
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)

users = []


async def send_message(to_username, msg):
    for user in users:
        if user['username'] == to_username:
            loop = asyncio.get_event_loop()
            connection = user["connection"]
            msg = msg.encode(FORMAT)
            msg_lenth = str(len(msg)).encode(FORMAT)
            header = msg_lenth + b' ' * (HEADER - len(msg_lenth))
            await loop.sock_sendall(connection, header)
            await loop.sock_sendall(connection, msg)
            break
    # we can add if check for if there is no user named like client want


def delete_connection(username):
    for (idx, user) in enumerate(users):
        if user['username'] == username:
            del users[idx]


async def handle_client(conn, addr):
    print("[New Connection] {addr} connected...")
    loop = asyncio.get_event_loop()
    connected = True
    while connected:
        max_lenth = await loop.sock_recv(conn, HEADER)
        max_lenth = max_lenth.decode(FORMAT)
        if max_lenth:
            max_lenth = int(max_lenth)
            msg = await loop.sock_recv(conn, max_lenth)
            msg = msg.decode(FORMAT)
            messages = msg.split(SEP)
            username = messages[0]
            print(f"{users}")
            if USERNAME_MESSAGE in msg:
                # first connect write to users list
                data = {
                    "username": username,
                    "connection": conn
                }
                users.append(data)
                continue

            elif DISCONNECT_MESSAGE in msg:
                # connection closed delete from user list
                print("[Disconnect] Disconnecting from server")
                delete_connection(username)
                connected = False
            elif len(messages) > 2:
                # one to one messagging
                print(f"[{addr}] message will send -> {msg}")
                to_username = messages[1]
                await send_message(to_username, msg)
    print(f"{len(asyncio.all_tasks())}")
    conn.close()


async def start():
    server.listen()
    print(f"[Listening] Server is Listening now on {IP}")
    loop = asyncio.get_event_loop()
    while True:
        conn, addr = await loop.sock_accept(server)
        loop.create_task(handle_client(conn, addr))


if __name__ == "__main__":
    print("[Starting] Socket Server is starting... Stand By")
    asyncio.run(start())

Kodu incelediğiniz de basit AsyncIO örneği ile benzerlikleri bulunduğunu göreceksiniz.

loop = asyncio.get_event_loop()
    while True:
        conn, addr = await loop.sock_accept(server)
        loop.create_task(handle_client(conn, addr))

Yukarıda ki kod parçacığını tekrar hatırlayacak olursak:

Yukarıdaki kodda loop’a atadığımız şey sistemin o anki çalıştırdığı taskları getirir. Eğer çalışan task yoksa yeni bir task listesi olusturup onu donduruyor. create_task ile fonksiyonumuz task listesine atıyoruz

Python ile Socket Programlama 2
if max_lenth:
    max_lenth = int(max_lenth)
    msg = await loop.sock_recv(conn, max_lenth)
    msg = msg.decode(FORMAT)
    messages = msg.split(SEP)
    username = messages[0]
    print(f"{users}")
    if USERNAME_MESSAGE in msg:
        # first connect write to users list
        data = {
            "username": username,
            "connection": conn
        }
        users.append(data)
        continue

    elif DISCONNECT_MESSAGE in msg:
        # connection closed delete from user list
        print("[Disconnect] Disconnecting from server")
        delete_connection(username)
        connected = False
    elif len(messages) > 2:
        # one to one messagging
        print(f"[{addr}] message will send -> {msg}")
        to_username = messages[1]
        await send_message(to_username, msg)

Kodumuzu incelediğimiz de mesajı aldıktan sonra işlemler yapıldığını görüyoruz. Gelin bu işlemleri inceleyelim.

if USERNAME_MESSAGE in msg:
    # first connect write to users list
    data = {
        "username": username,
        "connection": conn
    }
    users.append(data)
    continue

Mesajı aldıktan sonra ilk kez mi bağlantı oluşturduğunu anlamak için mesaj içerisine gömülmüş belirli bir yapıyı aratıyoruz. Eğer ilk kez bağlandıysa bağlantı bilgisini users adlı listeye ekliyoruz.

elif DISCONNECT_MESSAGE in msg:
    # connection closed delete from user list
    print("[Disconnect] Disconnecting from server")
    delete_connection(username)
    connected = False

İkinci olarak ise bağlantıyı koparmak isteyip istemediğini kontrol ediyoruz. Eğer belirlenmiş olan özel yapı mesaj içerisinde var ise bağlantı bilgilerini listeden silmesi için fonksiyona gönderiyoruz. Bilgileri listeden silindiğinde kullanıcılar bilgileri silinen kullanıcıya mesaj atamayacaklar.

elif len(messages) > 2:
    # one to one messagging
    print(f"[{addr}] message will send -> {msg}")
    to_username = messages[1]
    await send_message(to_username, msg)

Son olarak belli bir yapıya göre parse ettiğimiz mesajı mesaj, gönderen ve gönderdiği kişi gibi bilgiler var mı kontrol ediyoruz. Sonrasında mesajı “send_message” fonksiyonuna gönderiyoruz.

Client kodumuzu inceleyecek olursak Python Socket 1’e 1 Mesajlaşma Örneği(Thread ile) yazımda kullandığım client kodunun aynısı olduğunu göreceksiniz. Siz isterseniz bu kodu AsyncIO ile yazabilirsiniz.

import socket
from threading import Thread

HEADER = 64
PORT = 9999
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "DISCONNECT_SERVER_CODE"
USERNAME_MESSAGE = "EXAMPLE_APP_USERNAME_FIELD"
SEP = "///**//"
IP = socket.gethostbyname(socket.gethostname())
ADDR = (IP, PORT)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDR)


def send(msg):
    message = msg.encode(FORMAT)
    msg_lenth = str(len(message)).encode(FORMAT)
    header = msg_lenth + b' ' * (HEADER - len(msg_lenth))
    client.send(header)
    client.send(message)


def main(username, to_username):
    # send(f"{username}{SEP}{DISCONNECT_MESSAGE}")
    while True:
        message = input("")
        if message == "disconnect":
            send(f"{username}{SEP}{DISCONNECT_MESSAGE}")
        send(f"{username}{SEP}{to_username}{SEP}{message}")


def listen(username):
    # should check for main thread if it closed we need to terminate listen thread.
    connected = True
    while connected:
        max_lenth = client.recv(HEADER).decode(FORMAT)
        if max_lenth:
            max_lenth = int(max_lenth)
            msg = client.recv(max_lenth).decode(FORMAT)
            messages = msg.split(SEP)
            if len(messages) > 2:
                if messages[1] == username:
                    print(f"\n {messages[0]} -->  {messages[2]} \n")
                else:
                    print("security issue check server.py ")


if __name__ == "__main__":
    username = input("Please write your user name: ")
    if username:
        send(f"{username}{SEP}{USERNAME_MESSAGE}")
        to_username = input(f"who you will send message: ")
        print("you can write your message and press enter")
        main_thread = Thread(target=main, args=(username, to_username,))
        listen_thread = Thread(target=listen,  args=(username,))
        main_thread.daemon = True
        main_thread.start()
        listen_thread.start()

Python ile Socket Programlama Serimizin sonuna geldik.

Bu serimizde socket hakkında bilgiler verip, Thread ve AsyncIO ile socket yazılımları yazdık.

Tüm yazılara ulaşmak için -> Python Socket Programlama

Add a Comment

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir