Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
      Languages 
      Kernels 
      Packages 
      Books 
      Tests 
      OS 
      Forum 
      Математика 
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Assembler...2334 
 Advanced Bash Scripting G...2148 
 Ethreal 4...1682 
 Secure Programming for Li...1455 
 CPAN-> FAQ...1285 
 Ethreal 1...1077 
 Intel 386...1076 
 Go Web ...1062 
 Тренажёр...979 
 Trees...969 
 Alg1...940 
 Максвелл 3...922 
 William Gropp...889 
 Ext4 FS...868 
 Rust...860 
 C + UNIX...787 
 Go...756 
 Mod_parrot...733 
 Benchmark...725 
 System...703 
 
  01.01.2025 : 3803065 посещений 

iakovlev.org

Pusher

Код лежит тут

У меня на работе встал вопрос с реализацией удаленных прямых телевизионных трансляций . Нужно было написать TCP клиент-серверное приложение для их поддержки. Этот проект мы назвали Pusher - от слова толкать .
Рассмотрим схему:

 
 
                         ============                                                         ================
                         | клиент 1 |                                                   <-->  |  приемник 1  |
                         ============                                                         ================
    ==============       ============                                     ============        ================
    |  источник  | <-->  | клиент 2 |     <--- ... Интернет ...  ---->    |  сервер  |  <-->  |  приемник 2  |
    ==============       ============                                     ============        ================
                         ============                                                         ================
                         | клиент 3 |                                                   <-->  |  приемник 3  |
                         ============                                                         ================
 
 
 
Имеется веб-сервер с 'белым' ip-шником , к которому коннектятся приемники трансляции. На другом конце - источник трансляции , физически расположенный на клиентском компьютере с 'серым' ip-шником . Задача - передавать в real-time видео-поток с клиента на сервер .

Эта схема укладывается в традиционную архитектуру 'TCP client-server' . На сервере размещены 2 прослушивающих сокета : правый слушает запросы с серверного приемника , левый слушает запросы с клиентской машины. На клиенте - также 2 сокета , правый клиентский сокет коннектится к левому сокету сервера , левый клиентский сокет коннектится к источнику .

                                клиент
                           ================ 
                     <---->| 8003 | 8005  |<---->
                           ================
 
                                сервер 
                           ================ 
                     <---->| 8005 | 8007  |<---->
                           ================
 

Каждый раз , когда будет присоединяться новый приемник , на левом клиенте будет создаваться новый поток , который будет коннектиться к источнику и обслуживать данный приемник .

Для того , чтобы протестировать эту модель локально , мы возьмем в качестве источника и приемника медиа-проигрыватель VLC , который умеет вещать и делать http-запросы . Так , в качестве источника запустим VLC с параметрами :

vlc -vvv film.avi --sout '#standard{access=http,mux=asf,dst=127.0.0.1:8003}'

В нашей схеме источник будет вещать на порт 8003 , к которому будет коннектиться левый клиент .

Общение между правым клиентом и левым сервером будет происходить по порту 8005.

В качестве приемника запустим VLC с параметрами - можно запустить сразу несколько команд :

vlc http://127.0.0.1:8007

VLC в качестве приемника будет делать запросы на порт 8007 , который будет обслуживать правый сервер. Если вы сразу замените в локальном варианте порт 8007 на 8003 , то приемник непосредственно обратится к источнику , откроется окно VLC , и вы начнете смотреть фильм . В нашей схеме , если все правильно написано , в результате должно произойти то же самое - откроется VLC-ное окно для просмотра фильма .

Я написал сначала версию на питоне , позже сделал си-шный вариант .
Рассмотрим вариант на С .

Пушер имеет многопоточную архитектуру на базе pthread : такой выбор я сделал для удобства разделения логики работы. В проекте 2 многопоточных приложения - клиент и сервер . Два сокета внутри сервера разнесены по разным потокам , равно как и два сокета внутри клиента . Обмен данными между двумя потоками как внутри сервера , так и внутри клиента , выполняется через глобальные связные списки. Потоки внутри приложения также обращаются к глобальным структурам , доступ к которым синхронизирован с помощью стандартных блокировок .

В заголовок каждого фрейма записывается id-шник дескриптора приемника , которому предназначен этот фрейм . В нужный момент он парсится при получении .

Особенность локальной реализации , которая завязана на VLC , обуславливает следующую последовательность событий :

1. Правый слушающий сокет получает от приемника специфическую VLC-шную строку коннекта и сохраняет ее в глобальной переменной.
2. Левый слушающий сокет проверяет эту переменную и передает строку коннекта правому клиенту , который сохраняет ее в свою очередь также в глобальной переменной.
3. Левый клиент читает эту глобальную переменную и отдает строку источнику
4. Получив 'нормальную' строку коннекта , VLC начинает отдавать видео-данные левому клиенту, при этом создается отдельный поток для обслуживания данного приемника .
5. Левый tcp-клиент получает видео-данные и добавляет фрейм в связаный список client_frame. Он увеличивает счетчик фреймов и сообщает об правому клиенту , который может находиться в спячке .
6. Правый tcp-клиент , получив сообщение , просыпается , извлекает видео-данные из связного списка client_frame , сохраняет id-шник дескриптора приемника в заголовке фрейма, записывает фрейм в свой дескриптор , после чего уменьшает счетчик фреймов .
7. Левый tcp-сервер читает свой дескриптор и извлекает видео-данные из фрейма, получает id-шник дескриптора приемника из заголовка фрейма , после чего добавляет фрейм в связный список server_frame , затем увеличивает счетчик фреймов и сообщает об этом правому серверу , который может находиться в спячке .
8. Правый tcp-сервер просыпается , извлекает видео-данные из связного списка server_frame и записывает фрейм в свой дескриптор данного приемника , уменьшая счетчик фреймов .
9. Приемник получает свои данные , и вы начинаете смотреть фильм .

Если вы посмотрите в топ , то увидите , что и клиент , и сервер практически не потребляют мощности процессора. Вы сможете открыть столько приемников , сколько позволит ваш компьютер и графическая система .

В этой версии еще есть над чем поработать :
выключение работающего приемника в данной версии некорректное и приводит к перегрузке сервера .

Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье