Как реализовать WebSocket-сервер и клиент на Python?

«Как реализовать WebSocket-сервер и клиент на Python?» — вопрос из категории Сети, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

WebSockets предоставляют полнодуплексную (двустороннюю) связь между клиентом и сервером по одному TCP-соединению, что идеально подходит для приложений, требующих обмена данными в реальном времени (например, чаты, онлайн-игры, уведомления). В Python для работы с WebSockets часто используется асинхронная библиотека websockets.

Пример: Простой эхо-сервер и клиент на websockets

Этот пример демонстрирует, как создать сервер, который отправляет обратно любое полученное сообщение (эхо), и клиент, который отправляет сообщение и ожидает ответа.

1. Установка библиотеки:

pip install websockets

2. WebSocket-сервер (server.py):

import asyncio
import websockets

async def echo(websocket, path):
    """Обрабатывает входящие сообщения и отправляет их обратно."""
    print(f"Клиент подключен: {websocket.remote_address}")
    try:
        async for message in websocket:
            print(f"Получено от клиента {websocket.remote_address}: {message}")
            await websocket.send(f"Эхо: {message}")
    except websockets.exceptions.ConnectionClosedOK:
        print(f"Клиент {websocket.remote_address} отключился корректно.")
    except Exception as e:
        print(f"Ошибка с клиентом {websocket.remote_address}: {e}")
    finally:
        print(f"Клиент {websocket.remote_address} отключен.")

async def main():
    """Запускает WebSocket-сервер."""
    # Запускаем сервер на localhost, порт 8765
    async with websockets.serve(echo, "localhost", 8765):
        print("WebSocket-сервер запущен на ws://localhost:8765")
        await asyncio.Future()  # Сервер будет работать бесконечно

if __name__ == "__main__":
    asyncio.run(main())

3. WebSocket-клиент (client.py):

import asyncio
import websockets

async def send_message():
    """Подключается к серверу, отправляет сообщение и получает ответ."""
    uri = "ws://localhost:8765"
    async with websockets.connect(uri) as websocket:
        message = "Привет, WebSocket!"
        print(f"Отправка сообщения: {message}")
        await websocket.send(message)

        response = await websocket.recv()
        print(f"Получено от сервера: {response}")

if __name__ == "__main__":
    asyncio.run(send_message())

Как запустить:

  1. Запустите сервер в одном терминале: python server.py
  2. Запустите клиент в другом терминале: python client.py

Почему это эффективно:

  • Асинхронность: Использование asyncio позволяет серверу эффективно обрабатывать множество одновременных соединений без блокировки, что критично для высоконагруженных приложений.
  • Двусторонняя связь: Клиент и сервер могут отправлять и получать сообщения независимо друг от друга в любое время после установления соединения, в отличие от традиционного HTTP-запрос/ответ.
  • Реальное время: Минимальная задержка и отсутствие накладных расходов на повторное установление соединения делают WebSockets идеальными для интерактивных приложений, где важна мгновенная реакция.