# ФАЙЛ «SERVER\_SITE.PY»

Основные задачи файла:

1\. Получение данных о портах и RTSP-потоке: Из командной строки.

2\. Настройка сокетов и WebSocket соединений: Для приема и отправки данных.

3\. Захват видео с камеры: И отправка закодированных изображений клиентам.

4\. Асинхронное управление: Веб-сервером и сокетами, с использованием Tornado и asyncio.<br>

## ИНИЦИАЛИЗАЦИЯ БИБЛИОТЕК

```python
import asyncio
import base64
import contextlib
import io
import json
import sys
import threading
from PIL import Image
import cv2
import tornado.ioloop
import tornado.web
import tornado.websocket
import socket
```

\- asyncio: Модуль для асинхронного программирования.

\- base64: Модуль для кодирования и декодирования данных в формате base64.

\- contextlib: Контекстные менеджеры и утилиты для работы с ними.

\- io: Модуль для работы с потоками ввода/вывода.

\- json: Модуль для работы с JSON-данными.

\- sys: Модуль для работы с параметрами командной строки и другими системными функциями.

\- threading: Модуль для многопоточности.

\- PIL.Image: Библиотека для обработки изображений.

\- cv2: Библиотека OpenCV для обработки изображений и видео.

\- tornado.ioloop, tornado.web, tornado.websocket: Tornado - веб-фреймворк для создания веб-приложений и работы с WebSocket.

\- socket: Модуль для сетевого взаимодействия.

## ПАРАМЕТРЫ ПОДКЛЮЧЕНИЯ

```python
global mass
mass=None

if len(sys.argv) > 1:
    # Первый аргумент после имени скрипта будет содержать данные о портах    
    port_data = sys.argv[1]
    port_data = port_data.split(',')
    print(port_data)
    ports = port_data[0].split(':')    
    ports2 = port_data[1].split(':')
    ip_site=ports[0]
    port_site=ports[1]
    host = ports2[0]
    port = int(ports2[1])
    rtsp = port_data[2]
else:    
    print("Данные о портах не были переданы")
```

Этот блок кода обрабатывает аргументы командной строки, чтобы установить параметры подключения:

\- sys.argv: Используется для получения аргументов командной строки.

\- port\_data: Информация о портах для веб-сервера и RTSP потока.

## &#x20;НАСТРОЙКА СОКЕТА

```python
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
server_socket.bind((host, port))
server_socket.listen(5)
print(f"Server listening on {host}:{port}")
```

Здесь происходит создание и настройка сокета для прослушивания входящих соединений.

## ИНИЦИАЛЗАЦИЯ КЛАССА MainHandler

```python
class MainHandler(tornado.web.RequestHandler):
    """
        Обработка GET-запроса.

        Описание:
        Метод вызывается при получении GET-запроса от клиента. Он отвечает за рендеринг HTML-шаблона 'in.html'.
    """
    def get(self):
        self.render("in.html")
        
```

В этом классе происходит обработка GET-запроса и рендеринг HTML-шаблона.

## ИНИЦИАЛИЗАЦИЯ КЛАССА SimpleWebSocket

```python
class SimpleWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        """
        Обработка открытия WebSocket.

        Описание:
        Метод вызывается при установлении нового WebSocket соединения с клиентом. Он инициирует асинхронную задачу отправки обновлений клиенту.
        """
        print("WebSocket opened")
        asyncio.create_task(self.send_updates())

    async def send_updates(self):
        """
        Асинхронная отправка обновлений клиенту.

        Описание:
        Метод выполняется в бесконечном цикле, отправляя клиенту кадры (frame) и данные графика (plot), если они доступны. Использует глобальную переменную 'mass' для отправки данных графика.
        """
        while True:
            frame = get_frame()
            
            # plot_data = create_plotly_figure()
            if frame:
                await self.write_message(json.dumps({'type': 'frame', 'frame': frame}))
            global mass
            if not mass==None:
                await self.write_message(json.dumps({'type': 'plot', 'plot': mass}))
            await asyncio.sleep(0)  # Передача управления для обработки других задач

    def on_message(self, message):
        """
        Обработка входящих сообщений от клиента.

        Описание:
        Метод вызывается при получении сообщения от клиента. В текущей реализации метод не выполняет никаких действий.
        """
        # print(message)
        pass

    def on_close(self):
        """
        Обработка закрытия WebSocket.

        Описание:
        Метод вызывается при закрытии WebSocket соединения. Выводит сообщение о закрытии соединения.
        """
        print("WebSocket closed")


```

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

## ЗАХВАТ ВИДЕО

```python
cap=cv2.VideoCapture(rtsp)
def get_frame():
    """
    Захват кадра из видеопотока и его преобразование в строку base64.

    Библиотеки:
    - cv2: для захвата видео
    - io: для работы с потоками ввода/вывода
    - PIL: для работы с изображениями
    - base64: для кодирования данных в формат base64

    Возвращает:
    - str: Строка, содержащая изображение в формате JPEG, закодированное в base64.

    Описание:
    Функция захватывает кадр из видеопотока, преобразует его в формат JPEG и кодирует в строку base64.
    Если захват кадра не удался, функция возвращает None.
    """
    _, img = cap.read()
    if img is not None:
        buffer = io.BytesIO()
        pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        pil_img.save(buffer, format='JPEG')
        img_str = base64.b64encode(buffer.getvalue()).decode('utf-8')
        return img_str
    else:
        return None
```

В этом блоке кода инициализируется функция для захвата кадра из RTSP потока и его кодирования в формат base64.

## ЗАПУСК TORNADO

```python
async def start_tornado():
    """
    Настройка и запуск асинхронного веб-сервера Tornado.

    Библиотеки:
    - tornado.web: для создания веб-приложения
    - tornado.websocket: для работы с WebSocket
    - asyncio: для асинхронного программирования

    Параметры:
    - Нет параметров.

    Описание:
    Функция создает экземпляр веб-приложения Tornado с обработчиками для HTTP и WebSocket,
    запускает его на указанном IP-адресе и порту, и ожидает событий.
    """
    app= tornado.web.Application([
        (r"/", MainHandler),
        (r"/websocket", SimpleWebSocket),
    ])
    app.listen(port_site,ip_site)
    print(f"Сервер Tornado запущен на http://{ip_site}:{port_site}")
    await asyncio.Event().wait()

```

Это асинхронная функция для настройки и запуска веб-сервера Tornado.

## ОБРАБОТКА СОКЕТОВ

```python
def async_task():
    """
    Обработка входящих соединений и данных от клиентов.

    Библиотеки:
    - socket: для работы с сетевыми сокетами
    - threading: для многопоточности

    Параметры:
    - Нет параметров.

    Возвращает:
    - Ничего не возвращает.

    Описание:
    Функция ожидает входящие соединения на сокете сервера. При установлении соединения
    данные от клиента считываются и сохраняются в глобальной переменной `mass`.
    После обработки данных соединение закрывается.
    """
    global mass
    while True:
        client_socket, addr = server_socket.accept()
        print(f"Connected by {addr}")
        try:
            while True:
                data = client_socket.recv(65536).decode('utf-8')
                if not data:
                    mass=None
                    break
                mass=data
        finally:
            client_socket.close()
            print("Connection closed.")
            # return
```

Это функция для обработки входящих соединений через сокеты и получения данных от клиентов<br>

## ГЛАВНАЯ ФУНКЦИЯ

```python
async def main():
    # Создание задачи для асинхронной функции
    socket_thread = threading.Thread(target=async_task, daemon=True)
    socket_thread.start()
    with contextlib.suppress(KeyboardInterrupt):
        # Запуск сервера Tornado
        await start_tornado()
        socket_thread.join()
```

Это основная функция запуска, которая инициализирует поток для обработки сокетов и запускает сервер Tornado.

## ЗАВЕРШЕНИЕ РАБОТЫ

```python
if __name__ == "__main__":
    asyncio.run(main())
    server_socket.close()
    print("Server stopped.")
```

Здесь происходит закрытие сокета и сервера Tornado<br>

Процесс подготовки кода:

1. Создайте файл и назовите его Server\_site.py

<figure><img src="/files/A2hkvOWsYDFzndXR0c8Z" alt=""><figcaption><p>Файл Server_site.py в иерархии</p></figcaption></figure>

2. Поэтапно скопируйте код в файл:

<figure><img src="/files/0med306bWk8I1TYkVABp" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/1gR4zn5xdUFxiwOmKcXg" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/UJM8LIAH1TafMcKbyPqK" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Bws2U6oMxZEYmu25hs1c" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/DPIMt1H5wqHVIsMwcr6u" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/RitfMzx2hfW86pKEfjWq" alt=""><figcaption></figcaption></figure>

3. Установите необходимые библиотеки: в данном случае у нас не предустановлены следующие библиотеки: PIL (Pillow), cv2 и tornado. Если у вас не установлены эти библиотеки, выполните следующие действия:

   1. Откройте терминал VS Code (Terminal -> New Termial или комбинацией Ctrl + Shift + \`)
   2. В терминале поочередно введите и запустите следующие команды: pip install pillow; pip install opencv-python, pip install tornado


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dh-organization.gitbook.io/droneshub-rover-kontakt/opisanie-servernoi-chasti-programmy/fail-server_site.py.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
