← Kursa Dön
📄 Text · 18 min

Python ile Ağ Programlama: socket, requests ve HTTP

Bilgisayarların birbirleriyle konuşmasını hiç merak ettiniz mi? Her gün yaptığımız her şey — web sayfası açmak, mesaj göndermek, video izlemek — arka planda ağ programlamanın (network programming) esaslarına dayanıyor. Bu derste Python ile ağ dünyasına adım atacağız: düşük seviyeli socket programlamadan yüksek seviyeli HTTP isteklerine kadar her şeyi ele alacağız.


1. Ağ İletişimi Nedir?

Bilgisayarlar arasındaki iletişimi anlamak için bir telefon görüşmesi analojisi mükemmel çalışır. Birini aramak istediğinizde telefon numarasına (IP adresi) ve dahili hattına (port numarası) ihtiyacınız var. Karşı taraf telefonu açmalı (server dinlemeli) ve iki taraf da aynı dili konuşmalı (protokol).

IP Adresi ve Port

Her cihazın ağ üzerinde benzersiz bir adresi vardır — IPv4 formatında 192.168.1.1 gibi. Kendi bilgisayarınıza işaret eden özel adres 127.0.0.1 yani localhost'tur.

Port numarası ise gelen verinin hangi uygulamaya gideceğini belirler — bir binadaki daire numarası gibi. Portlar 0-65535 arasında değer alır: 80 (HTTP), 443 (HTTPS), 22 (SSH) gibi portlar standartlaşmıştır.

TCP vs UDP

TCP (Transmission Control Protocol) güvenilir iletişim sağlar. Veri paketleri sıralı gönderilir, kayıp olursa tekrar gönderilir. Telefon görüşmesi gibi — bağlantı kurulur, konuşulur, kapatılır.

UDP (User Datagram Protocol) ise hızlı ama garantisiz iletişimdir. Mektup göndermek gibi — postaya atarsınız ama teslim garantisi yoktur. Canlı yayın ve online oyunlarda hız önemli olduğu için UDP tercih edilir.

import socket

# TCP socket oluşturma
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# UDP socket oluşturma
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

print(f"TCP type: {tcp_socket.type}")   # SOCK_STREAM
print(f"UDP type: {udp_socket.type}")   # SOCK_DGRAM

tcp_socket.close()
udp_socket.close()

2. socket Modülü Temelleri

Python'un socket modülü, ağ programlamanın en temel yapı taşıdır. C dilindeki BSD socket API'sinin Python sarmalayıcısıdır (wrapper). Standart kütüphanede gelir, ekstra kurulum gerekmez.

Socket oluştururken iki parametre belirleriz: adres ailesi (address family) ve socket tipi. AF_INET IPv4 için, SOCK_STREAM TCP için, SOCK_DGRAM UDP için kullanılır.

import socket

hostname = socket.gethostname()
ip_address = socket.gethostbyname(hostname)
print(f"Hostname: {hostname}")
print(f"IP Address: {ip_address}")

# Bir domain'in IP adresini öğrenme
google_ip = socket.gethostbyname("www.google.com")
print(f"Google IP: {google_ip}")

# Port bilgisi sorgulama
http_port = socket.getservbyname("http")
print(f"HTTP port: {http_port}")
import socket

# Context manager ile socket kullanımı (önerilen yol)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.settimeout(5.0)
    try:
        s.connect(("www.google.com", 80))
        print("Connection successful!")
        print(f"Local: {s.getsockname()}")
        print(f"Remote: {s.getpeername()}")
    except socket.timeout:
        print("Connection timed out!")

💡 İpucu: Socket'leri her zaman with statement ile kullanın. Bu sayede bağlantı hata durumunda bile düzgün şekilde kapatılır. Manuel close() çağırmayı unutmak kaynak sızıntısına (resource leak) yol açar.


3. TCP Server Oluşturma

TCP server oluşturmak telefona cevap veren taraf olmak gibidir. Bir portu dinlersiniz, biri bağlantı isteği gönderdiğinde kabul edersiniz ve konuşmaya başlarsınız.

Temel adımlar: socket oluşturbindlistenacceptveri al/gönderkapat.

import socket

def start_tcp_server(host="127.0.0.1", port=65432):
    """Basit bir TCP server."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((host, port))
        server.listen(5)  # Maks 5 bekleyen bağlantı
        print(f"Server listening on {host}:{port}")

        conn, addr = server.accept()
        with conn:
            print(f"Connected by {addr}")
            data = conn.recv(1024)
            if data:
                print(f"Received: {data.decode('utf-8')}")
                conn.sendall(b"Message received!")

start_tcp_server()
import socket

def multi_client_server(host="127.0.0.1", port=65432):
    """Birden fazla client'ı sırayla kabul eden server."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((host, port))
        server.listen(5)
        print(f"Server ready on {host}:{port}")

        while True:
            conn, addr = server.accept()
            with conn:
                print(f"Client connected: {addr}")
                while True:
                    data = conn.recv(1024)
                    if not data:
                        break
                    conn.sendall(f"Echo: {data.decode()}".encode())
                print(f"Client disconnected: {addr}")

⚠️ Dikkat: SO_REUSEADDR seçeneğini her zaman ayarlayın. Bu olmadan, server'ı kapatıp hemen tekrar başlatmak istediğinizde "Address already in use" hatası alırsınız. İşletim sistemi portu bir süre meşgul tutar (TIME_WAIT durumu).


4. TCP Client Oluşturma

Client tarafı çok daha basittir: socket oluştur, server'a bağlan, veri gönder/al, kapat. Telefon analojisinde arayan taraf sizsiniz.

import socket

def tcp_client(host="127.0.0.1", port=65432, message="Hello, Server!"):
    """Basit bir TCP client."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
        client.connect((host, port))
        print(f"Connected to {host}:{port}")

        client.sendall(message.encode("utf-8"))
        print(f"Sent: {message}")

        response = client.recv(1024)
        print(f"Received: {response.decode('utf-8')}")

tcp_client()

send() ve sendall() arasındaki fark önemlidir. send() tüm veriyi göndermeyebilir, kaç byte gönderdiğini döner. sendall() ise tüm veri gönderilene kadar tekrar dener — çoğu durumda sendall() kullanmak daha güvenlidir.

import socket
import json

def send_json_to_server(host="127.0.0.1", port=65432):
    """JSON formatında veri gönderen client."""
    data = {
        "username": "pythondev",
        "action": "login",
        "timestamp": "2025-01-15T10:30:00"
    }
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
        client.settimeout(10.0)
        client.connect((host, port))
        client.sendall(json.dumps(data).encode("utf-8"))

        response = client.recv(4096)
        result = json.loads(response.decode("utf-8"))
        print(f"Server response: {result}")

5. Basit Echo Server Örneği

Echo server, gelen mesajı olduğu gibi geri gönderen klasik ağ programlama örneğidir. Ping-pong gibi düşünün: ne gönderirseniz, aynısı geri döner.

# echo_server.py
import socket

def echo_server(host="127.0.0.1", port=9999):
    """Gelen mesajı aynen geri gönderen echo server."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((host, port))
        server.listen(1)
        print(f"Echo server on {host}:{port}")

        while True:
            conn, addr = server.accept()
            with conn:
                print(f"[+] {addr} connected")
                while True:
                    data = conn.recv(1024)
                    if not data:
                        break
                    conn.sendall(data)  # Aynen geri gönder
                print(f"[-] {addr} disconnected")
# echo_client.py
import socket

def echo_client(host="127.0.0.1", port=9999):
    """Echo server'a mesaj gönderip cevabı alan client."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
        client.connect((host, port))
        messages = ["Hello!", "Python networking", "Echo test"]

        for msg in messages:
            client.sendall(msg.encode())
            response = client.recv(1024)
            print(f"Sent: {msg} → Got: {response.decode()}")

echo_client()

Bu iki dosyayı ayrı terminallerde çalıştırın: önce server'ı, sonra client'ı başlatın. Client'ın gönderdiği her mesajın birebir geri döndüğünü göreceksiniz.


6. UDP vs TCP — Ne Zaman Hangisi?

TCP ve UDP arasındaki seçim uygulamanızın ihtiyaçlarına bağlıdır. Genel kural: veri kaybı kabul edilemezse TCP, hız kritikse ve kayıp tolere edilebilirse UDP.

ÖzellikTCPUDP
BağlantıConnection-orientedConnectionless
GüvenilirlikGarantili, sıralıGaranti yok
HızDaha yavaşDaha hızlı
KullanımWeb, e-posta, dosyaDNS, streaming, oyunlar
# UDP Server — bağlantı kurulmaz, doğrudan veri alınır
import socket

def udp_server(host="127.0.0.1", port=9998):
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as server:
        server.bind((host, port))
        print(f"UDP server on {host}:{port}")
        while True:
            data, addr = server.recvfrom(1024)
            print(f"From {addr}: {data.decode()}")
            server.sendto(f"ACK: {data.decode()}".encode(), addr)
# UDP Client — connect gerekmez, doğrudan gönderilir
import socket

def udp_client(host="127.0.0.1", port=9998):
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as client:
        for msg in ["Ping", "Hello UDP", "Fast message"]:
            client.sendto(msg.encode(), (host, port))
            data, _ = client.recvfrom(1024)
            print(f"Reply: {data.decode()}")

udp_client()

UDP'de accept() ve listen() yok — çünkü bağlantı kavramı yoktur. Veriler sendto() ile gönderilir, recvfrom() ile alınır. Her paket bağımsızdır.


7. HTTP Protokolü Temelleri

HTTP (HyperText Transfer Protocol) web'in temel iletişim protokolüdür. Bir postane gibi düşünebilirsiniz: istek mektubu (request) gönderirsiniz, postane (server) mektubu işler ve cevap mektubu (response) geri gönderir. Her istek bağımsızdır — postane önceki mektuplarınızı hatırlamaz (stateless).

HTTP Metodları

  • GET — Veri iste (web sayfası aç, API'den veri çek)

  • POST — Veri gönder (form gönder, kayıt oluştur)

  • PUT — Mevcut veriyi tamamen güncelle

  • PATCH — Kısmi güncelleme

  • DELETE — Veri sil

Durum Kodları (Status Codes)

AralıkAnlamÖrnekler
2xxBaşarılı200 OK, 201 Created
3xxYönlendirme301 Moved, 304 Not Modified
4xxClient hatası400 Bad Request, 404 Not Found
5xxServer hatası500 Internal Error, 503 Unavailable
# HTTP isteğinin yapısı (kavramsal gösterim)
request_example = """
GET /api/users HTTP/1.1
Host: example.com
Accept: application/json
Authorization: Bearer abc123
"""

response_example = """
HTTP/1.1 200 OK
Content-Type: application/json

{"id": 1, "name": "Ali", "role": "developer"}
"""

print("=== Request ===", request_example)
print("=== Response ===", response_example)

HTTP, TCP üzerine kuruludur. Bir HTTP isteği yaptığınızda arka planda TCP bağlantısı açılır, istek metin olarak gönderilir ve cevap alınır. Kütüphaneler bu detayları bizim için halleder.


8. urllib ile HTTP İstekleri

Python'un standart kütüphanesindeki urllib modülü, HTTP istekleri yapmanın en temel yoludur. Ek kurulum gerektirmez, basit işler için yeterlidir.

from urllib.request import urlopen
from urllib.error import URLError, HTTPError
import json

url = "https://jsonplaceholder.typicode.com/posts/1"

try:
    with urlopen(url, timeout=10) as response:
        body = response.read().decode("utf-8")
        data = json.loads(body)
        print(f"Status: {response.status}")
        print(f"Title: {data['title']}")
except HTTPError as e:
    print(f"HTTP Error: {e.code} {e.reason}")
except URLError as e:
    print(f"URL Error: {e.reason}")
from urllib.request import urlopen, Request
import json

# POST isteği göndermek
url = "https://jsonplaceholder.typicode.com/posts"
payload = {"title": "Python Networking", "body": "urllib test", "userId": 1}

data = json.dumps(payload).encode("utf-8")
req = Request(url, data=data, method="POST")
req.add_header("Content-Type", "application/json")

with urlopen(req) as response:
    result = json.loads(response.read().decode())
    print(f"Created post ID: {result['id']}")

Gördüğünüz gibi urllib ile POST yapmak biraz zahmetli — veriyi encode etmek, Request objesi oluşturmak, header eklemek gerekiyor. Bu yüzden çoğu geliştirici requests kütüphanesini tercih eder.


9. requests Kütüphanesi

requests, Python'da HTTP istekleri yapmanın en popüler yoludur. "HTTP for Humans" sloganıyla geliştirilmiştir.

pip install requests

GET İsteği

import requests

response = requests.get(
    "https://jsonplaceholder.typicode.com/posts/1",
    timeout=10
)
print(f"Status: {response.status_code}")

data = response.json()  # Otomatik JSON parse
print(f"Title: {data['title']}")
print(f"User ID: {data['userId']}")

urllib ile yazdığımız 15 satırlık kodu requests ile 4-5 satırda hallettik. .json() otomatik parse eder, .text string olarak, .content bytes olarak erişim sağlar.

POST İsteği

import requests

payload = {
    "title": "Python Networking",
    "body": "requests makes HTTP easy",
    "userId": 1
}

response = requests.post(
    "https://jsonplaceholder.typicode.com/posts",
    json=payload,  # Otomatik JSON serialize + header
    timeout=10
)
print(f"Status: {response.status_code}")
print(f"Created: {response.json()}")

Headers ve Query Parameters

import requests

headers = {
    "Authorization": "Bearer my-secret-token",
    "Accept": "application/json"
}
params = {"userId": 1, "_limit": 5}

response = requests.get(
    "https://jsonplaceholder.typicode.com/posts",
    headers=headers,
    params=params,
    timeout=10
)
print(f"URL: {response.url}")  # Parametreler URL'ye eklenir
print(f"Found {len(response.json())} posts")

💡 İpucu: json= parametresi kullanırsanız, requests otomatik olarak Content-Type: application/json header'ını ekler ve veriyi serialize eder. data= kullanırsanız form-encoded gönderir. Bu ayrımı bilmek çok önemlidir!


10. REST API ile Çalışma — JSON Response Parse Etme

REST API'ler modern web uygulamalarının omurgasıdır. JSON formatı Python dictionary'lerine birebir karşılık geldiği için çalışması çok kolaydır.

import requests

response = requests.get(
    "https://jsonplaceholder.typicode.com/users",
    timeout=10
)
response.raise_for_status()  # Hata varsa exception fırlat

users = response.json()
for user in users[:5]:
    name = user["name"]
    email = user["email"]
    city = user["address"]["city"]
    print(f"{name} ({email}) - {city}")
import requests

# İlişkili veri çekme — zincirleme API çağrıları
base = "https://jsonplaceholder.typicode.com"

user = requests.get(f"{base}/users/1", timeout=10).json()
print(f"User: {user['name']}")

posts = requests.get(f"{base}/posts", params={"userId": 1}, timeout=10).json()
print(f"Posts: {len(posts)}")

if posts:
    comments = requests.get(
        f"{base}/comments", params={"postId": posts[0]["id"]}, timeout=10
    ).json()
    print(f"Comments on first post: {len(comments)}")

requests.Session() kullanmak, aynı server'a birden fazla istek yapacağınız senaryolarda performans ve kod temizliği sağlar. Session, TCP bağlantısını tekrar kullanır (connection pooling) ve ortak header'ları bir kez tanımlamanız yeterli olur.

import requests

session = requests.Session()
session.headers.update({"Accept": "application/json"})

users = session.get("https://jsonplaceholder.typicode.com/users").json()
posts = session.get("https://jsonplaceholder.typicode.com/posts").json()
print(f"Users: {len(users)}, Posts: {len(posts)}")
session.close()

11. Error Handling: timeout, ConnectionError, HTTPError

Ağ programlamada hatalar kaçınılmazdır. Server çökebilir, internet kopabilir, istek zaman aşımına uğrayabilir. Sağlam hata yönetimi şarttır.

import requests
from requests.exceptions import (
    ConnectionError, Timeout, HTTPError, RequestException
)

def safe_api_call(url, max_retries=3):
    """Hata yönetimli API çağrısı."""
    for attempt in range(1, max_retries + 1):
        try:
            response = requests.get(url, timeout=5)
            response.raise_for_status()
            return response.json()
        except Timeout:
            print(f"[{attempt}] Timeout — server yanıt vermedi")
        except ConnectionError:
            print(f"[{attempt}] Connection error — ağ sorunu")
        except HTTPError as e:
            print(f"[{attempt}] HTTP {e.response.status_code}")
            if e.response.status_code == 404:
                return None  # Tekrar denemenin anlamı yok
        except RequestException as e:
            print(f"[{attempt}] Unexpected: {e}")
    return None

result = safe_api_call("https://jsonplaceholder.typicode.com/posts/1")
if result:
    print(f"Got: {result['title']}")
import socket

def check_port(host, port, timeout=3):
    """Belirli bir host:port açık mı kontrol et."""
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(timeout)
            s.connect((host, port))
            return True
    except socket.timeout:
        print(f"{host}:{port} — timeout")
    except ConnectionRefusedError:
        print(f"{host}:{port} — refused")
    except socket.gaierror:
        print(f"{host} — DNS failed")
    return False

for host, port in [("google.com", 80), ("google.com", 443)]:
    status = "OPEN" if check_port(host, port) else "CLOSED"
    print(f"  {host}:{port} → {status}")

⚠️ Dikkat: Her ağ isteğinde mutlaka timeout parametresi kullanın! Timeout belirtmezseniz programınız sonsuza kadar bekleyebilir. API istekleri için 5-10 saniye, socket bağlantıları için 3-5 saniye makul değerlerdir.


12. Basit HTTP Server (http.server Modülü)

Python'un standart kütüphanesi tek satırla HTTP server başlatmanıza olanak tanır. Geliştirme ve test amaçlı mükemmeldir — production için kullanmayın!

# Mevcut dizini HTTP üzerinden paylaş
python -m http.server 8000

# Sadece localhost'tan erişim
python -m http.server 8000 --bind 127.0.0.1
from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class SimpleAPIHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/api/hello":
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            response = {"message": "Hello from Python!"}
            self.wfile.write(json.dumps(response).encode())
        else:
            self.send_response(404)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps({"error": "Not Found"}).encode())

    def do_POST(self):
        length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(length)
        data = json.loads(body.decode()) if body else {}

        self.send_response(201)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(json.dumps({"received": data}).encode())

if __name__ == "__main__":
    server = HTTPServer(("127.0.0.1", 8080), SimpleAPIHandler)
    print("API running on http://127.0.0.1:8080")
    server.serve_forever()

Bu örnekte BaseHTTPRequestHandler sınıfını genişleterek kendi endpoint'lerimizi oluşturduk. Gerçek projelerde Flask veya FastAPI gibi framework'ler çok daha pratiktir.


13. Async Networking — aiohttp Kısa Tanıtım

Klasik requests çağrıları bloklayıcıdır (blocking) — bir istek sonuçlanana kadar program bekler. Eşzamanlı birçok istek yapmanız gerektiğinde bu ciddi darboğaz olur.

aiohttp kütüphanesi, asyncio ile birlikte asenkron HTTP istekleri yapmanıza olanak tanır. Bir isteğin cevabını beklerken başka istekler gönderebilirsiniz.

pip install aiohttp
import asyncio
import aiohttp
import time

async def fetch_post(session, post_id):
    url = f"https://jsonplaceholder.typicode.com/posts/{post_id}"
    async with session.get(url) as response:
        data = await response.json()
        return data["title"]

async def fetch_all():
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_post(session, i) for i in range(1, 11)]
        results = await asyncio.gather(*tasks)
        for i, title in enumerate(results, 1):
            print(f"Post {i}: {title[:40]}...")

start = time.time()
asyncio.run(fetch_all())
print(f"\nAsync: {time.time() - start:.2f}s (10 concurrent requests)")
import asyncio
import aiohttp

async def fetch_safe(url):
    """Hata yönetimli asenkron istek."""
    try:
        timeout = aiohttp.ClientTimeout(total=5)
        async with aiohttp.ClientSession(timeout=timeout) as session:
            async with session.get(url) as resp:
                if resp.status == 200:
                    return await resp.json()
                print(f"HTTP {resp.status} for {url}")
    except asyncio.TimeoutError:
        print(f"Timeout: {url}")
    except aiohttp.ClientError as e:
        print(f"Error: {e}")
    return None

async def main():
    urls = [
        "https://jsonplaceholder.typicode.com/posts/1",
        "https://jsonplaceholder.typicode.com/users/1",
    ]
    results = await asyncio.gather(*[fetch_safe(u) for u in urls])
    for r in results:
        if r:
            print(f"Got data with {len(r)} fields")

asyncio.run(main())

Senkron requests ile 10 API çağrısı sırayla ~5-10 saniye sürebilir. aiohttp ile eşzamanlı yapıldığında ~0.5-1 saniyede tamamlanır. Ancak basit script'lerde requests yeterlidir — ölçeklenmeniz gerektiğinde async'e geçin.


14. Güvenlik: HTTPS, SSL/TLS Temel Bilgi

HTTP trafiği düz metin (plain text) olarak gönderilir — birisi ağ trafiğinizi dinlerse şifreler dahil her şeyi okuyabilir. HTTPS, HTTP'nin SSL/TLS şifreleme katmanı ile güvence altına alınmış halidir.

SSL (Secure Sockets Layer) ve modern versiyonu TLS (Transport Layer Security), veriyi şifreleyen protokollerdir. HTTPS'de veriler şifrelenir, değiştirilemez ve server'ın kimliği doğrulanır.

import ssl
import socket

def check_ssl_cert(hostname, port=443):
    """SSL sertifika bilgilerini gösterir."""
    context = ssl.create_default_context()
    with socket.create_connection((hostname, port), timeout=5) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            cert = ssock.getpeercert()
            subject = dict(x[0] for x in cert["subject"])
            issuer = dict(x[0] for x in cert["issuer"])
            print(f"Host: {hostname}")
            print(f"TLS: {ssock.version()}")
            print(f"Subject: {subject.get('commonName', 'N/A')}")
            print(f"Issuer: {issuer.get('organizationName', 'N/A')}")
            print(f"Expires: {cert['notAfter']}")

check_ssl_cert("www.google.com")
import requests

# HTTPS — requests varsayılan olarak sertifika doğrular
response = requests.get("https://www.google.com", timeout=5)
print(f"Status: {response.status_code}")

# verify=False TEHLİKELİ! Sadece test ortamında kullanın
# response = requests.get("https://self-signed.example.com", verify=False)

⚠️ Dikkat: Production kodda verify=False asla kullanmayın! SSL/TLS korumasını tamamen devre dışı bırakır ve uygulamanızı man-in-the-middle saldırılarına açık hale getirir. Self-signed sertifikalar için verify="/path/to/cert.pem" kullanın.

Güvenlik İpuçları

  • Her zaman HTTPS kullanın

  • API anahtarlarını kodda yazmayın, ortam değişkenleri (environment variables) kullanın

  • Timeout değerlerini her zaman ayarlayın

  • Hassas verileri URL query parameter'da göndermeyin, request body kullanın

import os
import requests

# API anahtarını ortam değişkeninden al
api_key = os.environ.get("API_KEY")
if not api_key:
    raise ValueError("API_KEY not set!")

response = requests.get(
    "https://api.example.com/data",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=10,
    verify=True
)

Özet

  • Socket programlama, ağ iletişiminin en alt seviyesidir. socket modülü ile TCP/UDP server ve client oluşturabilirsiniz. TCP güvenilir ama yavaş, UDP hızlı ama garantisizdir.

  • HTTP protokolü web'in iletişim dilidir. GET ile veri çekersiniz, POST ile gönderirsiniz. Durum kodları (200, 404, 500) server'ın yanıt durumunu bildirir.

  • `urllib` standart kütüphanede gelir, temel HTTP için yeterlidir. `requests` ise çok daha kullanıcı dostudur — .json(), session desteği, otomatik encoding ile günlük işleri kolaylaştırır.

  • Error handling ağ programlamanın olmazsa olmazıdır. Her istekte timeout belirleyin, try/except ile ConnectionError, Timeout, HTTPError hatalarını yakalayın.

  • Asenkron programlama (aiohttp) çok sayıda eşzamanlı HTTP isteği gerektiğinde büyük performans kazancı sağlar. Basit işlerde requests yeterlidir.

  • Güvenlik her zaman önceliğiniz olmalıdır: HTTPS kullanın, API anahtarlarını kodda yazmayın, sertifika doğrulamayı kapatmayın, timeout ayarlayın.


*Bir sonraki adım olarak Flask veya FastAPI ile gerçek web uygulamaları geliştirmeye geçebilirsiniz. Bu derste öğrendiğiniz socket ve HTTP temelleri, framework'lerin arka planını anlamanıza büyük katkı sağlayacaktır.*