Python ile basit portsuz chat programı

zztri

Yaşayan Forum Efsanesi
9 Tem 2015
10,061
388
Ankara
Yardım merkezindeki bir soruyu cevaplamak için hazırladığım bir programdır.

Öğrenilmesi beklenenler;

1. MySQL tipi veritabanlarının kullanımı
2. Threading

Hedefimiz basit; python kullanarak basit bir chat programı yapmayı planlamaktayız. Ara sunucu görevi gören yapı bir MySql veritabanı olacak, çünkü çok hızlı bir şekilde ücretsiz bir mysql veritabanı alabiliriz. Diğer yöntemlere uyarlamak kullanıcıya kalmıştır.

Bulduğum bedava veritabanları "ucuz etin yahnisi pek olur" sözüne uygun şekilde çok yavaş çıkınca sıkıldım. MariaDB, yani MySQL'in neredeyse bire bir aynı olan ücretsiz veritabanı sunucusunu kurdum.

Mariadb connector kurulu değilse pip ile kurmayı da unutmuyoruz.

python -m pip install mariadb

İlk iş olarak programımız veritabanı bağlantısını kurmalıdır.

Python:
import mariadb
import time
#time'ı sadece unix epoch dediğimiz ilk unix sistemi ortaya çıktığından beri kaç saniye
#geçtiğini bulmak için kullanacağız.
import threading
#threading namespace'i ayrı bir "thread" çalıştırmak için kullanılacak.

baglanti=mariadb.connect(host="localhost",user="root",password="[I]şifrem[/I]",database="chat")

Yani host, kullanıcı adı ve şifre parametrelerini verip veritabanına olan bağlantımızı oluşturduk.

Şimdi bu bağlantıya ait "cursor"ü alıp istediğimiz komutları işletebiliriz. Kürsor normalde "dolaşılabilen", yani en azından ileri gidilebilen bir veri dizisinde kaldığımız yeri gösteren belirteçtir. Python'da ise komutları da kürsörden giriyoruz. Anladığım kadarı ile MySQL tipi veritabanlarında MARS, yani aynı anda birden fazla işlem yapabilme özelliği yok. Ondan dolayı ben de kürsörleri kullanacağım anda oluşturup sonra kapatmayı seçtim. Araştırdığım kadarı ile bu verimsiz bir işlem değil, her bağlantının zaten bir cursor pool'u var ve sizin kapattıklarınızı tekrar kullanıyor.

Ardından ilk iş kullanıcıdan bir kullanıcı adı isteyelim.

Python:
while 1:
    isim=input("Adınızı giriniz: ")
    #Eğer python 3'den öncesini kullanıyorsanız raw_input kullanmanız gereklidir.
    #Bu bütün "input" komutları için geçerlidir.
    if (len(isim)>0 and len(isim)<21):
    #isim'in uzunluğu sıfırdan büyükse veya 21'den küçükse kurduğumuz sonsuz döngüden çıkıyoruz.
    #yoksa sonsuza dek istemeye devam ediyoruz.
    #daha güzel bir şekilde yapılabilir. Ben sadece hata mesajını engelliyorum.
        break
İsim boş olmamalı ve 20 hane veya daha aşağı olmalıdır. Bunun harici kendiniz istediğiniz kuralları ekleyebilirsiniz.

Ardından sadece kullanıcının yazdıklarını veritabanına aktaran kısma odaklanalım.

Python:
while 1:
    mesaj=input(">")
    #mesaj gireceği basit bir belirteç kullanıyoruz. Veritabanında "mesaj" kolonunun türü "text" olduğundan
    #dolayı canlarının istediği kadar büyük veri girsinler.
    if (len(mesaj)==0):
        continue
    #Eğer mesajın boyu sıfırsa, yani mesaj boşsa devam et, yani döngünün başına kadar ilerle diyoruz.
    with baglanti.cursor() as kursor:
        kursor.execute("insert into chat values(%s,%s,%s)",(isim,mesaj,time.time()))
    #execute komutunun ilk parametresi sql komutudur. Bu komutta sonradan eklemek istediğimiz
    #parametrelerin yerine %s koyarız. Sonra da bir tuple içinde bütün parametreleri gireriz.
    baglanti.commit()
    #commit etmezsek, yani değişiklikleri kaydetmezsek bu değişiklikler kaybolur.
Ne yaptık? Mesajı bekledik, eğer mesaj boş değilse bunu veritabanına "insert" ettik. Parametrelerin yerini %s ile işaretleyip sonradan grup olarak bu parametreleri verdik ki sql injection'la da uğraşmayalım, özel karakterleri escape etmekle de uğraşmayalım...

Şimdi bu alanın hemen öncesinde ise düzenli olarak mesajları okuyan bir yer gerekli değil mi? Önce bu işi yapan bir fonksiyon yazalım.

Python:
def mesajOku(isim,baglanti):
    sonOkuma=time.time()
    # ilk sefer için sadece şu andan itibaren gelecek mesajları istiyoruz.
    while 1:
        with baglanti.cursor() as kursor:
            kursor.execute("select isim,mesaj,zaman from chat where isim!=%s and zaman>%s order by zaman",(isim,sonOkuma))
            #Kendimizin olmayan ve son okumamızdan beri girilmiş olan mesajları istiyoruz.
            for mesajSatiri in kursor.fetchall():
            #gelen her mesaj için.....
                print(mesajSatiri[0]+"> "+mesajSatiri[1])
                #mesajı yazan kişi ve mesaj ekrana yazılır.
                sonOkuma=mesajSatiri[2]
                #sonra da son okuma zamanı veritabanındaki değerle güncellenir.
            baglanti.commit()
            #okuma işimiz bitti, yine commit ediyoruz.
        time.sleep(1)
        #sonra da 1 saniye uyusun...
Yani ne yaptık, bizim mesajımız olmayan ve en son okuduğumuz zamandan sonraki bütün mesajları zaman sırasıyla aldık, yazdık. 1 saniye uyuyup aynı işi tekrar tekrar yaptık.

Son yapmamız gereken bu fonksiyonu ayrı bir thread olarak çalıştırmak. Bunu da mesaj yazma döngüsünden hemen önce...

Python:
threading.Thread(target=mesajOku, args=(isim,kursor)).start()

deyiverip yapıyoruz.

Bütün kodu yazmamız gerekirse...

Python:
import mariadb
import time
import threading

def mesajOku(isim,baglanti):
    sonOkuma=time.time()
    while 1:
        with baglanti.cursor() as kursor:
            kursor.execute("select isim,mesaj,zaman from chat where isim!=%s and zaman>%s order by zaman",(isim,sonOkuma))
            for mesajSatiri in kursor.fetchall():
                print(mesajSatiri[0]+"> "+mesajSatiri[1])
                sonOkuma=mesajSatiri[2]
            baglanti.commit()
        time.sleep(1)
baglanti=mariadb.connect(host="127.0.0.1",user="root",password="[I]şifrem[/I]",database="chat")
while 1:
    isim=input("Adınızı giriniz: ")
    if (len(isim)>0 and len(isim)<21):
        break
threading.Thread(target=mesajOku, args=(isim,baglanti)).start()
while 1:
    mesaj=input(">")
    if (len(mesaj)==0):
        continue
    with baglanti.cursor() as kursor:
        kursor.execute("insert into chat values(?,?,?)",(isim,mesaj,time.time()))
        baglanti.commit()

Şimdi yerel veritabanında çalıştığını gördük. O zaman ne yapıyoruz? Önce bize Tor lazım. Bir vpn aracılığıyla girip Tor Expert Bundle'ı indiriyoruz. Ardından bir config dosyası yazıyoruz Tor için...

Python:
SOCKSPort 9050
#Yukarda yazdığımız port, Tor'un bağlantı beklediği port.
#kontrol portu koymuyorum. Gerek yok.
HiddenServiceDir d:\gizliservis
HiddenServicePort 3306 127.0.0.1:3306
#Diyoruz ki bir hidden service kur. Klasörü d:\gizliservis olsun.
#Bu gizli servisin 3306. portuna gelen her paketi benim bilgisayarımın 3306. portuna
#yönlendir.

Şimdi bunu kaydedip tor.exe'yi -f <torrc dosyası yeri> parametresiyle çalıştıralım.

Göreceğiniz gibi gizli servisiniz oluşacaktır. Gizliservis klasörüne baktığınızda "hostname" diye bir dosya göreceksiniz. Bunun içindeki adres sizin gizli servis adresinizdir.
 
Son düzenleme:

gikaa123

Kıdemli Üye
26 Haz 2012
2,605
61
Uzun zamandır forumda aktif görememiştim hocam sizi, elinize sağlık :)
 

Pikachu37

Yeni üye
21 May 2021
15
3
Güzel düşünce eline sağlık.
Bunun için Realtime db olarak Firebase kulansan çok daha iyi olabilir.
Hatta değişkenleri de standartlara uyma konusunda az daha sıkıştırıp ingilizce yapsan daha da güzel olabilirmiş.

Ayrıca kendini geliştirmeye hevesliysen bu linki de iyice sindirmende fayda olabilir.
 

suitdz1

Yeni üye
21 Mar 2021
5
1
Tam raw socket ile MySQL client yazıyor diye sevinç yaşadım, halbuki hazır modül kullanıyormuş. Neyse, eline sağlık
 
6 Tem 2021
155
19
33
Yardım merkezindeki bir soruyu cevaplamak için hazırladığım bir programdır.

Öğrenilmesi beklenenler;

1. MySQL tipi veritabanlarının kullanımı
2. Threading

Hedefimiz basit; python kullanarak basit bir chat programı yapmayı planlamaktayız. Ara sunucu görevi gören yapı bir MySql veritabanı olacak, çünkü çok hızlı bir şekilde ücretsiz bir mysql veritabanı alabiliriz. Diğer yöntemlere uyarlamak kullanıcıya kalmıştır.

Bulduğum bedava veritabanları "ucuz etin yahnisi pek olur" sözüne uygun şekilde çok yavaş çıkınca sıkıldım. MariaDB, yani MySQL'in neredeyse bire bir aynı olan ücretsiz veritabanı sunucusunu kurdum.

Mariadb connector kurulu değilse pip ile kurmayı da unutmuyoruz.



İlk iş olarak programımız veritabanı bağlantısını kurmalıdır.

Python:
import mariadb
import time
#time'ı sadece unix epoch dediğimiz ilk unix sistemi ortaya çıktığından beri kaç saniye
#geçtiğini bulmak için kullanacağız.
import threading
#threading namespace'i ayrı bir "thread" çalıştırmak için kullanılacak.

baglanti=mariadb.connect(host="localhost",user="root",password="[I]şifrem[/I]",database="chat")

Yani host, kullanıcı adı ve şifre parametrelerini verip veritabanına olan bağlantımızı oluşturduk.

Şimdi bu bağlantıya ait "cursor"ü alıp istediğimiz komutları işletebiliriz. Kürsor normalde "dolaşılabilen", yani en azından ileri gidilebilen bir veri dizisinde kaldığımız yeri gösteren belirteçtir. Python'da ise komutları da kürsörden giriyoruz. Anladığım kadarı ile MySQL tipi veritabanlarında MARS, yani aynı anda birden fazla işlem yapabilme özelliği yok. Ondan dolayı ben de kürsörleri kullanacağım anda oluşturup sonra kapatmayı seçtim. Araştırdığım kadarı ile bu verimsiz bir işlem değil, her bağlantının zaten bir cursor pool'u var ve sizin kapattıklarınızı tekrar kullanıyor.

Ardından ilk iş kullanıcıdan bir kullanıcı adı isteyelim.

Python:
while 1:
    isim=input("Adınızı giriniz: ")
    #Eğer python 3'den öncesini kullanıyorsanız raw_input kullanmanız gereklidir.
    #Bu bütün "input" komutları için geçerlidir.
    if (len(isim)>0 and len(isim)<21):
    #isim'in uzunluğu sıfırdan büyükse veya 21'den küçükse kurduğumuz sonsuz döngüden çıkıyoruz.
    #yoksa sonsuza dek istemeye devam ediyoruz.
    #daha güzel bir şekilde yapılabilir. Ben sadece hata mesajını engelliyorum.
        break
İsim boş olmamalı ve 20 hane veya daha aşağı olmalıdır. Bunun harici kendiniz istediğiniz kuralları ekleyebilirsiniz.

Ardından sadece kullanıcının yazdıklarını veritabanına aktaran kısma odaklanalım.

Python:
while 1:
    mesaj=input(">")
    #mesaj gireceği basit bir belirteç kullanıyoruz. Veritabanında "mesaj" kolonunun türü "text" olduğundan
    #dolayı canlarının istediği kadar büyük veri girsinler.
    if (len(mesaj)==0):
        continue
    #Eğer mesajın boyu sıfırsa, yani mesaj boşsa devam et, yani döngünün başına kadar ilerle diyoruz.
    with baglanti.cursor() as kursor:
        kursor.execute("insert into chat values(%s,%s,%s)",(isim,mesaj,time.time()))
    #execute komutunun ilk parametresi sql komutudur. Bu komutta sonradan eklemek istediğimiz
    #parametrelerin yerine %s koyarız. Sonra da bir tuple içinde bütün parametreleri gireriz.
    baglanti.commit()
    #commit etmezsek, yani değişiklikleri kaydetmezsek bu değişiklikler kaybolur.
Ne yaptık? Mesajı bekledik, eğer mesaj boş değilse bunu veritabanına "insert" ettik. Parametrelerin yerini %s ile işaretleyip sonradan grup olarak bu parametreleri verdik ki sql injection'la da uğraşmayalım, özel karakterleri escape etmekle de uğraşmayalım...

Şimdi bu alanın hemen öncesinde ise düzenli olarak mesajları okuyan bir yer gerekli değil mi? Önce bu işi yapan bir fonksiyon yazalım.

Python:
def mesajOku(isim,baglanti):
    sonOkuma=time.time()
    # ilk sefer için sadece şu andan itibaren gelecek mesajları istiyoruz.
    while 1:
        with baglanti.cursor() as kursor:
            kursor.execute("select isim,mesaj,zaman from chat where isim!=%s and zaman>%s order by zaman",(isim,sonOkuma))
            #Kendimizin olmayan ve son okumamızdan beri girilmiş olan mesajları istiyoruz.
            for mesajSatiri in kursor.fetchall():
            #gelen her mesaj için.....
                print(mesajSatiri[0]+"> "+mesajSatiri[1])
                #mesajı yazan kişi ve mesaj ekrana yazılır.
                sonOkuma=mesajSatiri[2]
                #sonra da son okuma zamanı veritabanındaki değerle güncellenir.
            baglanti.commit()
            #okuma işimiz bitti, yine commit ediyoruz.
        time.sleep(1)
        #sonra da 1 saniye uyusun...
Yani ne yaptık, bizim mesajımız olmayan ve en son okuduğumuz zamandan sonraki bütün mesajları zaman sırasıyla aldık, yazdık. 1 saniye uyuyup aynı işi tekrar tekrar yaptık.

Son yapmamız gereken bu fonksiyonu ayrı bir thread olarak çalıştırmak. Bunu da mesaj yazma döngüsünden hemen önce...

Python:
threading.Thread(target=mesajOku, args=(isim,kursor)).start()

deyiverip yapıyoruz.

Bütün kodu yazmamız gerekirse...

Python:
import mariadb
import time
import threading

def mesajOku(isim,baglanti):
    sonOkuma=time.time()
    while 1:
        with baglanti.cursor() as kursor:
            kursor.execute("select isim,mesaj,zaman from chat where isim!=%s and zaman>%s order by zaman",(isim,sonOkuma))
            for mesajSatiri in kursor.fetchall():
                print(mesajSatiri[0]+"> "+mesajSatiri[1])
                sonOkuma=mesajSatiri[2]
            baglanti.commit()
        time.sleep(1)
baglanti=mariadb.connect(host="127.0.0.1",user="root",password="[I]şifrem[/I]",database="chat")
while 1:
    isim=input("Adınızı giriniz: ")
    if (len(isim)>0 and len(isim)<21):
        break
threading.Thread(target=mesajOku, args=(isim,baglanti)).start()
while 1:
    mesaj=input(">")
    if (len(mesaj)==0):
        continue
    with baglanti.cursor() as kursor:
        kursor.execute("insert into chat values(?,?,?)",(isim,mesaj,time.time()))
        baglanti.commit()

Şimdi yerel veritabanında çalıştığını gördük. O zaman ne yapıyoruz? Önce bize Tor lazım. Bir vpn aracılığıyla girip Tor Expert Bundle'ı indiriyoruz. Ardından bir config dosyası yazıyoruz Tor için...

Python:
SOCKSPort 9050
#Yukarda yazdığımız port, Tor'un bağlantı beklediği port.
#kontrol portu koymuyorum. Gerek yok.
HiddenServiceDir d:\gizliservis
HiddenServicePort 3306 127.0.0.1:3306
#Diyoruz ki bir hidden service kur. Klasörü d:\gizliservis olsun.
#Bu gizli servisin 3306. portuna gelen her paketi benim bilgisayarımın 3306. portuna
#yönlendir.

Şimdi bunu kaydedip tor.exe'yi -f <torrc dosyası yeri> parametresiyle çalıştıralım.

Göreceğiniz gibi gizli servisiniz oluşacaktır. Gizliservis klasörüne baktığınızda "hostname" diye bir dosya göreceksiniz. Bunun içindeki adres sizin gizli servis adresinizdir.
peki bunla torsuz nasıl chat yaparız direk python kodu ve mariadb yeter mi olur mu???
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.