← Назад к вопросам
Как происходит клиент серверное взаимодействие?
1.3 Junior🔥 241 комментариев
#REST API и HTTP#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Клиент-серверное взаимодействие
Клиент-серверная архитектура — это парадигма, где клиент отправляет запросы серверу, а сервер обрабатывает и возвращает ответы. Разберём это на всех уровнях абстракции.
1. Сетевой уровень (OSI Model)
Взаимодействие проходит через несколько слоёв:
# Layer 7 (Application) — HTTP/REST API
# Layer 4 (Transport) — TCP/UDP
# Layer 3 (Network) — IP адреса
# Layer 2 (Data Link) — MAC адреса
# Layer 1 (Physical) — электрические сигналы
import socket
# TCP сокет (Layer 4)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("example.com", 80)) # IP, Port
sock.send(b"GET / HTTP/1.1\r\n") # HTTP request
response = sock.recv(4096) # HTTP response
sock.close()
2. TCP/IP протокол трёхстороннего handshake
Перед передачей данных устанавливается соединение:
import socket
# Клиент инициирует SYN пакет
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("server.com", 443))
# За кулисами происходит:
# 1. Клиент → Сервер: SYN (seq=x)
# 2. Сервер → Клиент: SYN-ACK (seq=y, ack=x+1)
# 3. Клиент → Сервер: ACK (seq=x+1, ack=y+1)
# Теперь соединение установлено (ESTABLISHED)
print("TCP соединение установлено")
sock.close()
3. HTTP протокол (Request-Response)
import requests
from typing import Dict, Any
# HTTP запрос имеет структуру:
headers: Dict[str, str] = {
"Host": "api.example.com",
"User-Agent": "Python-Client/1.0",
"Content-Type": "application/json",
"Authorization": "Bearer token123"
}
body = {"name": "John", "age": 30}
# Запрос
response = requests.post(
"https://api.example.com/users",
json=body,
headers=headers,
timeout=10
)
# HTTP ответ имеет структуру:
print(f"Status Code: {response.status_code}") # 200, 404, 500 и т.д.
print(f"Headers: {response.headers}") # Content-Type, Set-Cookie и т.д.
print(f"Body: {response.json()}") # Данные
# Request:
# POST /users HTTP/1.1
# Host: api.example.com
# Content-Length: 25
# Content-Type: application/json
#
# {"name":"John","age":30}
# Response:
# HTTP/1.1 201 Created
# Content-Type: application/json
# Content-Length: 40
#
# {"id":123,"name":"John","age":30}
4. Асинхронный REST API сервер
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel
import asyncio
app = FastAPI()
class UserCreate(BaseModel):
name: str
age: int
class UserResponse(BaseModel):
id: int
name: str
age: int
# Сервер слушает входящие запросы
@app.post("/users")
async def create_user(user: UserCreate) -> UserResponse:
# Сервер:
# 1. Получает запрос
# 2. Парсит JSON
# 3. Валидирует данные (Pydantic)
# 4. Обрабатывает логику
# 5. Возвращает ответ
# Имитация сохранения в БД
await asyncio.sleep(0.1)
return UserResponse(id=1, name=user.name, age=user.age)
@app.get("/users/{user_id}")
async def get_user(user_id: int) -> UserResponse:
if user_id < 1:
raise HTTPException(status_code=400, detail="Invalid ID")
# Поиск пользователя
return UserResponse(id=user_id, name="John", age=30)
5. WebSockets (двусторонняя коммуникация)
Для real-time данных используются WebSockets:
from fastapi import WebSocket, WebSocketDisconnect
from typing import List
class ConnectionManager:
def __init__(self):
self.active_connections: List[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
# Отправить сообщение всем клиентам
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
@app.websocket("/ws/chat")
async def websocket_endpoint(websocket: WebSocket):
await manager.connect(websocket)
try:
while True:
# Получить сообщение от клиента
data = await websocket.receive_text()
# Отправить всем подключённым клиентам
await manager.broadcast(f"Message: {data}")
except WebSocketDisconnect:
manager.disconnect(websocket)
6. gRPC (альтернатива REST)
Для микросервисов с высокой производительностью:
import grpc
from concurrent import futures
from typing import Iterator
# .proto файл определяет контракт
class UserServicer:
def GetUser(self, request, context):
# Бинарный протокол (Protocol Buffers)
# Быстрее и компактнее чем JSON
return {"id": 1, "name": "John"}
def StreamUsers(self, request, context) -> Iterator:
# Server streaming — отправить много данных
for i in range(100):
yield {"id": i, "name": f"User {i}"}
# Запустить gRPC сервер
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
server.add_insecure_port("[::]:50051")
server.start()
7. Полный цикл взаимодействия
import requests
import time
from typing import Dict, Any
def client_server_cycle() -> None:
# КЛИЕНТ отправляет запрос
url = "https://api.example.com/users"
payload = {"name": "Alice", "email": "alice@example.com"}
# Шаг 1: DNS lookup
# api.example.com → 93.184.216.34
# Шаг 2: TCP handshake (три пакета)
# Клиент → Сервер → Клиент
# Шаг 3: TLS handshake (HTTPS)
# Обмен сертификатами и ключами
# Шаг 4: Отправка HTTP запроса
start = time.time()
response = requests.post(
url,
json=payload,
timeout=30
)
elapsed = time.time() - start
print(f"Response time: {elapsed:.3f}s")
print(f"Status: {response.status_code}")
print(f"Body: {response.json()}")
# За кулисами на сервере:
# 1. Получение пакета
# 2. Парсинг HTTP заголовков и тела
# 3. Маршрутизация к нужному обработчику
# 4. Валидация данных
# 5. Обработка бизнес-логики (БД, кэш и т.д.)
# 6. Формирование ответа
# 7. Отправка обратно клиенту
client_server_cycle()
8. Обработка ошибок и timeouts
import requests
from requests.exceptions import (
Timeout,
ConnectionError,
HTTPError
)
def robust_request(url: str) -> Dict[str, Any] | None:
try:
response = requests.get(
url,
timeout=5, # Timeout в 5 секунд
retries=3 # Retry 3 раза
)
response.raise_for_status() # Если 4xx или 5xx
return response.json()
except Timeout:
print("Server took too long to respond")
return None
except ConnectionError:
print("Failed to connect to server")
return None
except HTTPError as e:
print(f"HTTP Error: {e.response.status_code}")
return None
9. Load Balancing и масштабирование
# В production много серверов за load balancer:
#
# Клиент → Load Balancer (nginx/HAProxy)
# ↓
# ┌──────┼──────┐
# ↓ ↓ ↓
# Server1 Server2 Server3
#
# Load Balancer распределяет запросы:
# - Round Robin (по очереди)
# - Least Connections (к серверу с меньше соединений)
# - IP Hash (по IP клиента)
# - Weighted (с учётом мощности сервера)
10. Безопасность
# HTTPS/TLS для шифрования
# - Все данные шифруются
# - Проверяется сертификат сервера
# - Защита от Man-in-the-Middle атак
import ssl
context = ssl.create_default_context()
context.check_hostname = True
context.verify_mode = ssl.CERT_REQUIRED
# Authentication и Authorization
# - Token (JWT, Bearer)
# - Basic Auth (username:password)
# - OAuth2, OpenID Connect
headers = {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Итоговая схема
КЛИЕНТ СЕРВЕР
↓
└─ DNS Lookup (IP)
└─ TCP Handshake (3-way)
└─ TLS Handshake (HTTPS)
└─ HTTP Request (POST /users)
└─────────────────────────→ Receive
Parse
Validate
Process
Database
←───────────────────────── HTTP Response
└─ Parse Response
└─ Render Data
Это фундамент для понимания всех типов интеграций: REST API, WebSockets, gRPC и микросервисной архитектуры.