Как реализовать WebSocket-сервер и клиент на 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 идеальными для интерактивных приложений, где важна мгновенная реакция.

Ответ 18+ 🔞

А, ВебСокеты, говоришь? Ну это же, блядь, та самая магия, когда клиент и сервер могут орать друг на друга одновременно, не перебивая, как две бабки у подъезда! Полнодуплексная связь, ёпта! Одно ТСП-соединение — и пошла писать губерния: чаты, игры, уведомления летят туда-сюда, в рот меня чих-пых!

В Питоне за это безобразие отвечает библиотечка websockets. Асинхронная, конечно, потому что иначе как, блядь, тысячу пользователей обслуживать? Каждому по отдельному потоку? Да ну нахуй, с ума сошли.

Смотри, как это выглядит вживую. Сначала, ясное дело, эту самую библиотеку надо впихнуть в систему.

pip install websockets

Ну вот, установили. Теперь давай на коленке сервак состряпаем, который будет как попугай — всё, что услышит, тут же обратно и ляпнет. Эхо-сервер, блядь, классика жанра.

Сервер (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())

Видишь эту асинхронную хуйню? async def, await? Это чтобы сервер не вставал в коленно-локтевую, пока один клиент думает, что ему сказать. Он в это время других может обслуживать, хитрая жопа!

А вот и клиентик, который придет пообщаться.

Клиент (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. Он скажет, что слушает порт 8765.
  2. В другом терминале, быстро-быстро: python client.py. Он пришлёт "Привет" и получит своё же "Привет" обратно, но уже с припиской "Эхо:".

И всё, ёпта! Связь установлена. Теперь они могут болтать, пока кран не отрубят.

А в чём, собственно, соль-то, блядь?

  • Асинхронность: Это как официант в ебучем адском ресторане, который не стоит над одним клиентом, ждёт, пока тот меню изучит, а бегает между столиками, всем понемногу внимания уделяет. Так и сервер — тысячи соединений, и ни одно не простаивает.
  • Двусторонний поток: Это не тот убогий HTTP, где ты запросил — жди ответа, как дурак. Тут можно на сервер строчить сообщения пачками, а он тебе в это же время может уведомления пихать. Одним словом, разговор на равных, а не начальник и подчинённый.
  • Реальное время, ёба: Задержки — минимальные, соединение одно и держится. Не надо каждый раз рукопожатия TCP и HTTP-хидеры гонять. Отправил — долетело. Идеально для всего, где важна скорость, а не бюрократия.

Вот так вот, простыми словами. Не благодари.