EtherDaler
@EtherDaler
Еще зеленый

Почему Websocket разрывает соединение c клиентом?

У меня есть приложение на FastApi, которое трекает правильность выполнения упражнения с помощью mediapipe. Я устанавливаю соединение клиента с сервером через websocket, но спустя какое-то время соединение разрывается. На сервер я передаю json, в котором передаются некоторые данные и зашифрованные в Base64 фреймы с камеры пользователя. Обратно сервер передает количество повторений на момент фрейма.
Так выглядит мой веб сокет:
@router.websocket("")
async def workout_connection(websocket: WebSocket):
    global connections

    connection_id = str(uuid.uuid4())
    await websocket.accept()

    connections[connection_id] = {"websocket": websocket, "video_frames": []}
    logger.info(f"New WebSocket connection: {connection_id}")

    try:
        while True:
            data_json = await websocket.receive_json()
            if "type" not in data_json:
                continue

            if data_json["type"] == "reset":
                connections[connection_id]["repetitions_count"] = 0
                connections[connection_id]["video_frames"] = []
                await websocket.send_json(
                    {
                        "type": "reset",
                        "connection_id": connection_id,
                    }
                )
                continue

            if data_json.get("is_resting", False):
                await websocket.send_json(
                    {
                        "type": "rest",
                        "connection_id": connection_id,
                    }
                )
                continue

            exercise_type = data_json["type"]

            if data_json.get("is_downloading", False):
                continue

            video_b64 = data_json["data"]
            video_bytes = base64.b64decode(video_b64)

            np_array = np.frombuffer(video_bytes, np.uint8)
            img = cv2.imdecode(np_array, cv2.IMREAD_COLOR)

            if exercise_type == "high_knees":
                frame, _, repetitions_count = process_high_knees(
                    img, connections[connection_id]
                )
            elif exercise_type == "jumping_jacks":
                print(f"outside excercis = {connections[connection_id]}")
                frame, _, repetitions_count = process_jumping_jacks(
                    img, connections[connection_id]
                )
            elif exercise_type == "side_lunge":
                frame, _, repetitions_count = side_lunge(
                    img, connections[connection_id]
                )
            elif exercise_type == "side_kick":
                frame, _, repetitions_count = side_kick(
                    img, connections[connection_id]
                )
            elif exercise_type == "bycicle":
                frame, _, repetitions_count = bycicle(
                    img, connections[connection_id]
                )
            elif exercise_type == "leg_swings":
                frame, _, repetitions_count = leg_swings(
                    img, connections[connection_id]
                )
            elif exercise_type == "melnica":
                frame, _, repetitions_count = melnica(
                    img, connections[connection_id]
                )
            elif exercise_type == "leg_abduption":
                frame, _, repetitions_count = leg_abduption(
                    img, connections[connection_id]
                )
            elif exercise_type == "pushups":
                frame, _, repetitions_count = pushups(
                    img, connections[connection_id]
                )
            elif exercise_type == "move_plank":
                frame, _, repetitions_count = move_plank(
                    img, connections[connection_id]
                )
            elif exercise_type == "plank":
                frame, _, repetitions_count = plank(
                    img, connections[connection_id]
                )
            elif exercise_type == "climbers_steps":
                frame, _, repetitions_count = climbers_steps(
                    img, connections[connection_id]
                )
            elif exercise_type == "kick":
                print(f"outside excercis = {connections[connection_id]}")
                frame, _, repetitions_count = kick(
                    img, connections[connection_id]
                )
            elif exercise_type == "standing_curls":
                frame, _, repetitions_count = standing_curls(
                    img, connections[connection_id]
                )
            elif exercise_type == "pelvic_lift":
                frame, _, repetitions_count = pelvic_lift(
                    img, connections[connection_id]
                )
            elif exercise_type == "pelvic_static":
                frame, _, repetitions_count = pelvic_static(
                    img, connections[connection_id]
                )
            elif exercise_type == "leg_raises_elbow_rest":
                frame, _, repetitions_count = leg_raises_elbow_rest(
                    img, connections[connection_id]
                )
            elif exercise_type == "sqats":
                frame, _, repetitions_count = sqats(
                    img, connections[connection_id]
                )
            elif exercise_type == "sqats_static":
                frame, _, repetitions_count = sqats_static(
                    img, connections[connection_id]
                )
            elif exercise_type == "press":
                frame, _, repetitions_count = press(
                    img, connections[connection_id]
                )
            elif exercise_type == "upor_lezha":
                frame, _, repetitions_count = upor_lezha(
                    img, connections[connection_id]
                )
            else:
                frame, _, repetitions_count = process_jumping_jacks(
                    img, connections[connection_id]
                )

            await websocket.send_json(
                {
                    "type": "count",
                    "data": repetitions_count,
                    "connection_id": connection_id,
                }
            )
        except WebSocketDisconnect:
            del connections[connection_id]
            logger.info(f"WebSocket connection closed: {connection_id}")
            print(f"WebSocket connection closed: {connection_id}")
            try:
                await websocket.close()
            except:
                pass


Вот что как отправляет данные JS:
function bufferToBase64(buffer) {
  let binary = "";
  let bytes = new Uint8Array(buffer);
  let len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}


function startVideoProcessing() {
  startTime = Date.now();
  const canvas = document.createElement("canvas");
  const context = canvas.getContext("2d");

  function sendFrame() {
    if (video.paused || video.ended) return;

    const aspectRatio = video.videoWidth / video.videoHeight;
    const targetHeight = 360;
    const targetWidth = aspectRatio * targetHeight;

    canvas.width = targetWidth;
    canvas.height = targetHeight;
    context.drawImage(video, 0, 0, targetWidth, targetHeight);

    canvas.toBlob(
      (blob) => {
        if (blob) {
          blob.arrayBuffer().then((buffer) => {
            let b64Data = isResting ? null : bufferToBase64(buffer);
            const data = JSON.stringify({
              type: currentExercise.exercise_id,
              data: b64Data,
              is_resting: isResting,
              is_downloading: isDownloading,
              is_completed: isCompleted,
            });
            ws.send(data);
          });
        }
      },
      "image/jpeg",
      0.5
    );

    setTimeout(sendFrame, interval);
  }
  setInterval(updateTimer, 1000);
  sendFrame();
}


Вот какую ошибку вижу в логах контейнера:
[2024-09-05 01:29:16 +0000] [18] [ERROR] Exception in ASGI application
Traceback (most recent call last):
  ...
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

Понятно как бы, что ожидаются двойные кавычки, но почему ошибка не всплывает сразу, а через некоторое время, и где там может не хватать кавычек?
Вот такого рода json приходят:
{"type":"sqats","data":"/9j/4AAQSkZJRgA...(Зашифрованный фрейм)","is_resting": false, "is_downloading": false, "is_completed": false}
  • Вопрос задан
  • 153 просмотра
Решения вопроса 1
EtherDaler
@EtherDaler Автор вопроса
Еще зеленый
Друзья, проблема решилась, я просто нормально прописал keep-alive (ping pong) соединение между клиентом и сервером.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы