> For the complete documentation index, see [llms.txt](https://bytistan.gitbook.io/baytistan/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bytistan.gitbook.io/baytistan/arka-kapi/sunucu-kontrol-programi.md).

# Sunucu - Kontrol Programı

Sunucunun kodlanmasında için `python` dilini ve  `socket` kütüphanesini seçtim.

## Temel Yapının Kurulması

Programın bağlantı kurması, şuan değil ama ileride dosya indirip yükleyebilmesi gibi bazı özelliklere sahip olması gerek. Nesne tabanlı programlamadığım zaman bu metotların kontrol etmem ve yeni özellikler eklemem bir hayli zorlaşıyor. O yüzden kuralına uygun ilerliyorum.

### Dosyanın Oluşturulması

Siz istediğiniz adı verebilirsiniz, ben `server` adında bir dosya oluşturuyorum.

```bash
touch server.py
```

### Bağımlılıkların İçe Aktarılması

```python
import socket
```

`socket` kütüphanesini dosya içerisine aktarıyorum, bilgisayarlar arası veri iletiminde kullanılan bir kütüphane.

### Sınıf ve Metotların Oluşturulması

Direk herhangi bir nesne kullanmadan da programlama yapılabilirdi ama doğrusu varken neden eksik veya yanlış üzerinden anlatım yapayım demi.

```python
# ...

class Server:
    def __init__(self):
        # ...
        pass
       
    def listen(self):
        # ...
        pass

# ...
```

Sınıf ve metot yapısı bu şekilde nesne tabanlı programlamaya dikkat ediyorum.

***

## IP ve Port Numarası ile Socket'in Bağlanması

Bağlantı noktasının oluşturulabilmesi için IP adresi ve port numarası gibi değişkenlere ihtiyaç var. Bu değişkenler belirlendikten sonra, sunucumu bu noktaya bağlayabilirim.

```python
#...

def __init__(self):
    self.ip = "192.168.1.106"
    self.port = 5000  
    
    self.connection = socket.socket()  
    self.connection.bind((self.ip, self.port))  
    
#...
```

`socket.socket()` ile bir socket nesnesi oluşturuyorum. Normalde 2 tane parametre alır:

* **İlk parametre:** Adres  tipini belirtir, varsayılan olarak `AF_INET` (IPv4) kullanır.&#x20;
* **İkinci parametre:** Protocol belirtir, varsayılan olarak `SOCK_STREAM` (TCP) kullanır.&#x20;

`self.connection.bind((self.ip, self.port))` kısmında ise, oluşturduğum `socket` nesnesini kullanarak daha önceden belirlediğim IP adresini ve port numarasına bağlanıyorum.

{% hint style="danger" %}
Burada kendi local IP adresini kullanman gerek.&#x20;

* Linux -> **`ifconfig`**
* Windows -> **`ipconfig`**&#x20;

İşletim sisteminize göre yukarıdaki komutları cmd veya terminale yazıldığında, elde edilen çıktı içerisindeki 192.168.xxx.xxx ifade yerel (local) IP adresini ifade etmektedir..
{% endhint %}

### Bağlantı İsteklerinin Kabul Edilmesi

Kimse evine tanımadığı birini almak istemez; bu nedenle kontrol yapılmasa da, gelen isteklerin kabul edilmesi ve yönetilmesi için bir alanın olması gerekli.

```python
#...

def listen(self):
    self.connection.listen(2)
    
    print("[+] Server start to listening: " + self.ip + ":" + str(self.port))
    
    conn, address = self.connection.accept()  
    
    print("[+] Connection from: " + str(address))
    
    #...
#...

```

`self.connection.listen(2)` sunucuya kaç tane istemcinin bağlanabileceği belirliyorum, burada 2.&#x20;

`self.connection.accept()` ile gelecek bağlantılar beklenmekte, metot herhangi bir istemci bağlanmadan diğer satıları işlemez, eğer herhangi bir istemci bağlanırsa bu metot iki tane değer döner:&#x20;

* **Birincisi:** Yeni bir`socket` nesnesi, istemci ile iletişimin yönetilmesinde kullanılıyor.
* **İkincisi:**  Bağlanan istemcinin adresi (yani IP adresi ve port numarası).

***

### İstemci ile İletişimin Sürdürülmesi

```python
#...

def listen(self):    
    #...
    
    while True:

        message = input(" -> ")
        
        conn.send(message.encode())  
    
        data = conn.recv(1024).decode()
    
        if not data:
            break
    
        print(str(data))

conn.close()

#...

```

İstemciden gelen bilgilerin sürekli olarak işlenmesi ve bağlantının kopmaması için sonsuz bir döngü oluşturuyorum.&#x20;

İstemciye gönderilecek olan komutu `input` aracılığı ile alıp `data` değişkenine atıyorum.&#x20;

`conn.send(data.encode())` metot'unu kullanarak istemciye yolluyorum.&#x20;

{% hint style="info" %}
`encode() metot'unun` kullanılmasının sebebi `string` ifadeyi `byte` türüne dönüştürmek.
{% endhint %}

***

`conn` yani bağlantı nesnesinin `recv`  metot'unu kullanarak, 1024 byte genişliğinde bir dinleme yapıyorum.`decode()` kullanarak `string` hale çeviriyorum ki anlamlı hale gelsin.

Herhangi bir `data` gelmediği zaman döngüyü sonlandırıyorum, gelmiş ise yazdırıyorum.

***

Döngü tamamlandığı zaman ise `conn.close()` metot'unu kullanarak bağlantıyı sonlandırıyorum.

{% hint style="warning" %}
Eğer bağlantı doğru kapanmaz, yani program hata sonucu veya başka sebeplerden kapanırsa, program yeniden başlatıldığında  çalışmayabilir. Bunun sebebi ilgili port'un `socket` tarafından kullanılmaya devam etmesidir. port değiştirilerek veya port temizlenerek sorun çözülebilir.
{% endhint %}

***

## Nesnesin Başlatılması

Son olarak oluşturduğum nesneyi başlatıyorum.

```python
if __name__ == '__main__':
    server = Server()
    server.listen()
```

Sunucu kısmı tamam şimdi sıra istemci tarafını kodlamakta.
