← Назад к вопросам

Какие протоколы может использовать WebSocket?

1.2 Junior🔥 201 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Протоколы, используемые WebSocket

WebSocket — это протокол, который работает поверх других протоколов, специально разработанный для полнодуплексного общения между клиентом и сервером в реальном времени.

1. WebSocket поверх HTTP/HTTPS (основной механизм)

Вебсокет использует HTTP для установления соединения, затем переходит на собственный протокол:

# На стороне сервера (FastAPI)
from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket('/ws')
async def websocket_endpoint(websocket: WebSocket):
    # HTTP Upgrade запрос
    # GET /ws HTTP/1.1
    # Upgrade: websocket
    # Connection: Upgrade
    # Sec-WebSocket-Key: ...
    
    await websocket.accept()
    
    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f'Echo: {data}')
    except Exception as e:
        await websocket.close()

Процесс установления соединения:

1. Клиент отправляет HTTP GET запрос с заголовками:
   GET /ws HTTP/1.1
   Host: example.com
   Upgrade: websocket
   Connection: Upgrade
   Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
   Sec-WebSocket-Version: 13

2. Сервер отвечает 101 Switching Protocols:
   HTTP/1.1 101 Switching Protocols
   Upgrade: websocket
   Connection: Upgrade
   Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

3. Теперь соединение переходит на WebSocket протокол

2. WebSocket поверх TCP (ws://)

Несекретный протокол WebSocket:

# Клиентский код (JavaScript)
const socket = new WebSocket('ws://localhost:8000/ws');

socket.onopen = () => {
    console.log('Connected');
    socket.send('Hello');
};

socket.onmessage = (event) => {
    console.log('Received:', event.data);
};

Процесс:

1. Клиент устанавливает TCP соединение с сервером на порту 80 (по умолчанию)
2. Отправляет HTTP Upgrade запрос
3. Сервер отвечает с переключением протокола
4. Данные передаются в фреймах WebSocket

3. WebSocket поверх TLS/SSL (wss://)

Защищенный вебсокет, аналог HTTPS:

# Клиент подключается к защищенному вебсокету
const socket = new WebSocket('wss://example.com/ws');

# Это шифрует всю коммуникацию end-to-end

Преимущества wss://

# На сервере (Uvicorn с SSL)
# uvicorn app:app --ssl-keyfile=key.pem --ssl-certfile=cert.pem

from fastapi import FastAPI, WebSocket

@app.websocket('/ws')
async def websocket_endpoint(websocket: WebSocket):
    # Все данные шифруются TLS
    await websocket.accept()
    
    data = await websocket.receive_text()
    # Данные защищены от перехвата
    await websocket.send_text(f'Secure: {data}')

Всегда использовать wss:// в production вместо ws://!

4. WebSocket фреймы (собственный протокол)

После установления соединения используется собственный формат фреймов:

Все данные разбиваются на фреймы:

Frame:
  FIN (1 бит)              - это последний фрейм?
  opcode (4 бита)          - тип данных (text=1, binary=2, close=8, ping=9, pong=10)
  MASK (1 бит)             - замаскированы ли данные?
  payload length (7-63 бита) - длина данных
  Mask key (32 бита, опционально)
  Payload data             - сами данные
# Пример с websockets модулем
import asyncio
import websockets

async def server(websocket, path):
    async for message in websocket:
        # Сервер получает распарсенный фрейм
        print(f'Message: {message}')
        await websocket.send(f'Echo: {message}')

async def main():
    async with websockets.serve(server, 'localhost', 8765):
        await asyncio.Future()  # run forever

asyncio.run(main())

5. Типы фреймов WebSocket

from fastapi import WebSocket, WebSocketDisconnect

@app.websocket('/ws')
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    
    try:
        while True:
            # 1. Text фрейм (opcode=1)
            data = await websocket.receive_text()
            print(f'Text: {data}')
            
            # 2. Binary фрейм (opcode=2)
            binary_data = await websocket.receive_bytes()
            print(f'Binary: {binary_data}')
            
    except WebSocketDisconnect:
        # 3. Close фрейм (opcode=8)
        print('Client disconnected')
        await websocket.close(code=1000)  # Normal closure

Opcodes (коды операций):

0x0 = Continuation frame
0x1 = Text frame
0x2 = Binary frame
0x8 = Connection close
0x9 = Ping
0xA = Pong

6. Ping/Pong механизм (keep-alive)

Для проверки живого соединения:

import asyncio
from fastapi import WebSocket, WebSocketDisconnect

@app.websocket('/ws')
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    
    async def keepalive():
        while True:
            try:
                await websocket.send_json({'type': 'ping'})
                await asyncio.sleep(30)  # ping каждые 30 секунд
            except:
                break
    
    asyncio.create_task(keepalive())
    
    try:
        while True:
            data = await websocket.receive_text()
            if data == 'pong':
                continue  # Connection is alive
            await websocket.send_text(f'Echo: {data}')
    except WebSocketDisconnect:
        print('Client disconnected')

7. WebSocket поверх HTTP/2 (экспериментально)

Новый стандарт для лучшей производительности:

# Некоторые серверы начинают поддерживать WebSocket на HTTP/2
# Это дает лучшую производительность при количественных подключениях

# На данный момент это не стандартизировано,
# но работается над RFC для WebSocket on HTTP/2

8. Базовая конструкция WebSocket пакета

# Полный пример обмена
from fastapi import FastAPI, WebSocket
import json

app = FastAPI()

@app.websocket('/chat')
async def websocket_chat(websocket: WebSocket):
    # 1. Handshake (HTTP Upgrade)
    await websocket.accept()
    
    try:
        while True:
            # 2. Получение текстового фрейма
            data = await websocket.receive_text()
            message = json.loads(data)
            
            # 3. Отправка текстового фрейма обратно
            response = {
                'type': 'message',
                'content': message['content'],
                'timestamp': '2024-03-22T10:30:00Z'
            }
            await websocket.send_text(json.dumps(response))
            
            # Можно также отправить бинарные данные
            # await websocket.send_bytes(binary_data)
            
    except Exception as e:
        # 4. Close фрейм
        await websocket.close(code=1000, reason=str(e))

9. Close коды WebSocket

from fastapi import WebSocket

@app.websocket('/ws')
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    
    try:
        data = await websocket.receive_text()
    except:
        pass
    
    # Различные коды закрытия:
    # 1000 - Normal closure
    await websocket.close(code=1000, reason='Normal')
    
    # 1001 - Going away
    await websocket.close(code=1001)
    
    # 1002 - Protocol error
    await websocket.close(code=1002)
    
    # 1003 - Unsupported data
    await websocket.close(code=1003)
    
    # 1006 - Abnormal closure (без фрейма)
    # await websocket.close(code=1006)
    
    # 1009 - Message too big
    await websocket.close(code=1009)
    
    # 1011 - Internal error
    await websocket.close(code=1011, reason='Server error')

10. Сравнение с альтернативами

# WebSocket (двусторонний, low-latency)
@app.websocket('/ws')
async def ws(websocket: WebSocket):
    await websocket.accept()
    async for msg in websocket.iter_text():
        await websocket.send_text(msg)

# Server-Sent Events (односторонний, легче для браузера)
@app.get('/sse')
async def sse():
    async def event_generator():
        for i in range(10):
            yield f'data: Event {i}\n\n'
    return StreamingResponse(event_generator(), media_type='text/event-stream')

# Polling (неэффективный)
@app.get('/poll')
async def poll():
    return {'data': get_latest_updates()}  # Клиент запрашивает каждую секунду

Итоговая таблица протоколов

ПротоколПортШифрованиеUse Case
ws://80НетDevelopment, demo
wss://443TLS/SSLProduction
HTTP Upgrade80/443OptionalМеханизм установления
TCPКастомныйНетКастомные протоколы
Фреймы WSP-Внутри TLSОбмен данными

Вся современная разработка должна использовать wss:// для защиты данных и обхода firewall'ов.