# ФАЙЛ «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="https://1021729848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRjxA8VkpxYSN3xTlTEOb%2Fuploads%2F2on5T2x9Q8OjT79G9WvO%2Fimage.png?alt=media&#x26;token=0f10f0af-ecb2-4572-86c1-329b1537ada1" alt=""><figcaption><p>Файл Server_site.py в иерархии</p></figcaption></figure>

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

<figure><img src="https://1021729848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRjxA8VkpxYSN3xTlTEOb%2Fuploads%2FxIEghock7ZQJNr1ta2En%2Fimage.png?alt=media&#x26;token=d4eed09c-9b92-43fc-b630-150d5cf643a1" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1021729848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRjxA8VkpxYSN3xTlTEOb%2Fuploads%2FLhiqMBlHIgRGDsCh8XpH%2Fimage.png?alt=media&#x26;token=37510849-3692-44fb-bc1b-48acdb37803c" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1021729848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRjxA8VkpxYSN3xTlTEOb%2Fuploads%2Fd9RsOvYeVx7C5ZGTNxT8%2Fimage.png?alt=media&#x26;token=1ffefaa3-0e5b-475a-a02d-0f251ec1f9cd" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1021729848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRjxA8VkpxYSN3xTlTEOb%2Fuploads%2FuaCCPH29WIaHXbudSByC%2Fimage.png?alt=media&#x26;token=3cb4dc03-0fd1-44ec-99d2-d08d9f3ef8b0" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1021729848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRjxA8VkpxYSN3xTlTEOb%2Fuploads%2F48tfO159z8syMiiDEBsv%2Fimage.png?alt=media&#x26;token=368f538b-e647-40b5-95cb-a4fae178ecdc" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1021729848-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRjxA8VkpxYSN3xTlTEOb%2Fuploads%2FuouXpxYO8ETNhHzzASts%2Fimage.png?alt=media&#x26;token=5c77f2cd-7499-4eb6-b376-edf7a27e5836" 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
