websocket... на Си... имеет ли кто опыт?

Тема в разделе "Флудилка", создана пользователем Igor68, 5 май 2018.

  1. Igor68

    Igor68 Гуру

    Доброго времени суток!
    ...собственно в этом названии темы и вопрос.
    Ранее всё делал на сокетах... сервер, который что-то выполняет... ну и клиент, который в большинстве случаев является только интерфейсом к процессу на сервере (на работе всё давно делаю по этой схеме).
    Клиент как правило на Windows... да ещё под каждый из них надо компилировать отдельно. Где 64 бита, где 32. Где XP, где семёрка и т.д. Муторно... просто стон. Хотелось было QtCreator... да не понял с окружением для машин, где он не установлен.
    С серверами проще... там в основном Linux, который почти ничего не требует. Вот и подумал про взаимодействие через браузер. Ну а остальное понятно.
    Делал через PHP + BASH + Ccode на стороне сервера, а клиент HTML + JS. И то и другое (HTML, PHP, JS) почти не знаю и пользуюсь глядя на примеры. Но вот схема СОЕДИНЕНИЕ-ЗАПРОС-ОТВЕТ-РАЗЪЕДИНЕНИЕ не очень. Очень долго существуют остановленные соединения (старые) на стороне WEB сервера (У меня везде Apache). Да и задержки даже при запросах JS для JSON.
    Вот и прошу совета и/или помощи.
    Вот брал примеры в google и тут:
    https://istarik.ru/blog/programmirovanie/73.html
    https://github.com/websockets/ws
    и опираясь на примеры начал делать заготовку-шаблон:
    websock3.zip
    Пока что он (сервер) умеет только начало... приём соединений с разбором параметров. Хотелось бы реализовать обработку по протоколу websocket с вызовом нужных функций при обработке принятых данных.
    На PHP есть примеры обработки... испытал. Да уж больно тяжело и медленно. Потому и хочу на Си.
    Если имеете опыт поделитесь, если не в тягость. Библиотеки, что по указанной ссылен (https://github.com/websockets/ws) не нужны... требуют доустановки ещё библиотек. На многие имеющиеся устройства (MOXA) просто нет возможности что-то доустановить. У меня не вышло добавить что-то для Perl, а он "голый" уже установлен на устройстве. А вот кросс-компилятор с либами и т.д. предоставлен. В Линуксе как в Линуксе... всё, что компилирую для Debian без затруднений переносится при помощи компиляции того же для Moxa.
    В файле Makefile (прилагается) выбирается компилятор.
    А create.sh запускает компиляцию и переносит всё необходимое в work... где всё готово для работы.
    Заранее благодарен!
     

    Вложения:

    • websock3.zip
      Размер файла:
      89,7 КБ
      Просмотров:
      420
    arkadyf нравится это.
  2. ZAZ-965

    ZAZ-965 Гуру

    В OpenWrt сталкивался с библиотекой Mongoose. Сам не писал, примеры программ читабельные.
     
    Igor68 нравится это.
  3. Igor68

    Igor68 Гуру

    Благодарю!
    Действительно код читабельный! Читаю...
     
  4. Igor68

    Igor68 Гуру

    Доброго времени суток!
    Вот это
    websock3.zip

    сейчас в состоянии после приёма запроса поддерживать соединение PING-PONG... после приёма первого запроса (тест HTML+JS) приложен.
    Собственно и вопросы исходя из того , что не знаком с JS (пользуюсь глядя на примеры) :
    - есть ли возможность сделать сервер с OpenCV... картинка от камеры на форму HTML в браузере онлайн. Тут поднималась тема не раз.
    - передавать команды тому же серверу.
    - какая-нибудь программа с интерфейсом через WEB страницу (процессы оборудования онлайн, игрушка и т.п.)
    Интересует возможность реализации, опыт и т.п.
    Со стороны приложений на Си вопрос вообще не стоит... а вот со стороны WEB браузера с JS на странице множество непонятного - приём допустим картинки, её построение в плане применения websocket. Видел исходники ну к примеру:
    HTML:
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <!--<link rel="stylesheet" href="style.css" type="text/css" />-->
            <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
            <!--<script src="jquery.js"></script>-->
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
     
            <style type="text/css">
               .knopka {
               height: 40px;
               width: 120px;
               text-align: center;
               line-height: 2.1;
               cursor: pointer;
               border: 1px solid #999;
               border-radius: 10px;}
               v{}
            </style>
            <script type="text/javascript">
                $(function() {
                    window.WebSocket = window.WebSocket || window.MozWebSocket;
                    var websocket = new WebSocket('ws://192.168.5.196:86/ws');

                    websocket.onopen = function () {
                        $('h1').css('color', '#65c178'); /* green */
                    };

                    websocket.onclose = function (e) {
                        console.log("WebSocket: ", e)
                        $('h1').css('color', '#fe457e'); /* red */
                    };

                    websocket.onerror = function () {
                        $('h1').css('color', '#fe457e'); /* red */
       
                    };

                    websocket.onmessage = function (message) {
                        console.log(message.data);
                        $('v').append($('<p>', { text: message.data }));
                    };
                   
                    $('.knp0').click(function(e) {
                        e.preventDefault();
                        websocket.send($('input').val());
                        $('input').val('');
                    });

                    $("input[id='text-count']").keydown(function count() {
                        number = $("input[id='text-count']").val().length + 1;
                        $("#count").html(" The number of bytes: " + number);
                    });

                    $('.knp1').click(function(e) {
                        e.preventDefault();
                        websocket.send("hi");
                    });

                    $('.knp2').click(function(e) {
                        e.preventDefault();
                        websocket.send("ping");
                    });

                    $('.knp3').click(function(e) {
                        e.preventDefault();
                        websocket.send("close");
                    });

                });
            </script>
            </head>
        <body>
            <h1>WebSocket</h1>
       
              <div class='knopka knp1'>Hi...</div>
              <div class='knopka knp3'>Close</div>
              <div class='knopka knp2'>Call PING</div>
              <div class='knopka knp0'>Send</div> <input type="text" id="text-count"/><span id="count"></span>
              <v></v>
        </body>
    </html>
     
    И почему (откуда взяли) это:
    HTML:
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    Вроде как не на моём локальном сервере... а где-то там:confused:
    И почему? И вообще что это за мода
    HTML:
    <link href="http://fonts.googleapis.com/css?family=Roboto+Slab:400,700|Roboto:300,400,500,700,400italic|Roboto+Condensed:300,400,700&subset=latin,cyrillic" rel="stylesheet" type="text/css">
    И не только на этом форуме... создаёт тормоза бешеные... пока не заблокировал.
    Спасибо!
     

    Вложения:

    • websock3.zip
      Размер файла:
      91,4 КБ
      Просмотров:
      412
  5. ZAZ-965

    ZAZ-965 Гуру

    По поводу скриптов с сайта Гугла - технология CDN (Content Distribution Network). Популярная библиотека jquery у пользователя с большой вероятностью уже в кэше, у CDN настроены все заголовки для сжатия и кэширования контента, снижается нагрузка на твой сервер, библиотека всегда с последними секьюрити патчами.
     
    Igor68 нравится это.
  6. Igor68

    Igor68 Гуру

    Понял так, что её надо скачать и разместить рядом с HTML кодом на локальном WEB сервере... при этом изменив ссылку в этом самом HTML. Ведь выхода в Инет там не будет... и он там ни к чему вообще.
     
  7. Igor68

    Igor68 Гуру

    И ещё: использую соединение через прокси, на малине.
    по схеме:
    pc <--wlan0-->3Proxy(Raspberry Pi 3)<--wlan1-->Dir620<--WAN-->интернет
    Малина... точнее сервер на ней настроен на минимальное использование дискового пространства. Настроил как мог, что бы SD карта не умерла быстро. Наверное ещё и там тормоза. Но кино онлайн смотрю спокойно через прокси... вопросов нет. А вот отсутсвие тормозов как говорил ранее только при блокировании адреса на браузере.
     
  8. Igor68

    Igor68 Гуру

    Доброго времени суток!
    Опять... ну или снова прошу Вашей помощи(подсказки)...
    И опять про websocket сервер. Пока сервер... ну или опять. На Си.
    На питоне то, что хотел имеется тут:
    https://istarik.ru/blog/programmirovanie/73.html
    А эта тема, что интересует:
    https://github.com/mrsin/k-lab/wiki/Передача-изображения-с-камеры-через-WebSocket
    Вот только незадача... на питоне.
    Что сделано (только как тест):
    Браузер Firefox подключается к серверу... передаёт текстовые сообщения. Сервер делает PING и получает от браузера PONG. Ну всё вроде, как надо. Вот незадача:
    Умею формировать фигуры на BMP файле. (Ранее уже приводил пример). Да... только в формате BMP... с остальными форматами не разбирался. Всё работает. Только ранее работа шла с файлом, а сейчас переделываю работу с буфером, который изначально заполняется из файла и в процессе работы все изменения в буфере копируются в этот файл. Сам сервер производит изменения в буфере. Он может брать картинку от камеры, формировать игровое поле, формировать панель виртуального прибора и т.п. Вот только транслировать картинку в браузер пока не умею (о чём и прошу). С управлением (подачи команд серверу) вопрос не стоит. Всё отрабатывается как текстовые данные. Тут как пример построения основываясь на указанных ссылках:
    Если пробуете на малине... то запускайте содержимое после компиляции на RAM диске! Не дайте умереть своей SD карте! Перезапись файла work.bmp производится приблизительно два раза в секунду. Делал для проверки.
    websock4.zip
    На картинке (файл "work.bmp") производится отрисовка окружности на экране (как тест). Точнее отрисовка в буфере сервера, который циклически записывает себя полностью в файл ("шапка" файла, его параметры - палитра, разрешение, содержимое и т.д.) Задача в том, чтобы сервер отдавал это браузеру в реальном времени, а не как я ранее делал через HTTP запросы от этого браузера.
    Вот и прошу помощи.
    Спасибо.
     

    Вложения:

    • websock4.zip
      Размер файла:
      406,4 КБ
      Просмотров:
      461
    Последнее редактирование: 12 май 2018
  9. Igor68

    Igor68 Гуру

    Доброго времени суток!
    ...понимаю, наверное задаю глупые вопросы... ну или это никто не делал и/или никому не интересно.
    Буду копать дальше. Жаль только Гугл ничего не говорит... ну или я не умею задавать вопросы.:confused:
     
  10. ИгорьК

    ИгорьК Гуру

    Их лучше задавать на другом форуме: www.cyberforum.ru/
    Здесь не тот контингент для таких вопросов.
     
    Igor68 нравится это.
  11. Igor68

    Igor68 Гуру

    Благодарю!
     
  12. DEgorov

    DEgorov Нерд

    С сокетами ты вроде и так разобрался, я на Си (да и вообще с нуля по RFC) их никогда не делал, поэтому тут и советы раздавать не буду -- ты лучше меня знаешь как там и чего.

    А про браузер имею сказать следующее. Есть несколько способов заставить браузер отрисовать картинку из данных. Как минимум подойдут canvas и генерация картинки из base64 потока. Второе проще -- там нужен минимум джаваскрипта. Делается это следующим образом:

    1) В теле документа должна быть картинка заготовлена без src просто пустая. Её можно создавать динамически через new Image() при желании, но можно и просто:

    HTML:
    <img id="frame" width="320" height="240">
    2) В эту картинку вставляется в качестве src-атрибута понятная браузеру строка:

    Код (Javascript):
    document.getElementById('frame').setAttribute('src', 'data:image/bmp;base64,' + DATA);
    Как именно ты будешь получать эти base64 закодированные данные (переменная DATA), разницы нет вообще. Можешь передавать через вебсокеты сразу закодированную по сути текстовую строку. Можешь передавать бинарные данные и закодировать их в base64 уже на стороне клиента -- это уже отдельный вопрос.

    Я приложил минимально возможный пример, в котором 3 base64 закодированных в строки кадра в цикле сменяются по очереди. Тебе нужно просто заменить эти строки на данные, полученные с сервера.

    Для base64 кодирования я воспользовался https://www.base64-image.de а картинки в паинте нарисовал :)

    А вообще, по-хорошему, тебе надо забить на вебсокеты и воспользоваться MJPEG. Там можно сделать просто одну картинку, указывающую на url, в который сервер будет отдавать по сути один JPEG файл за другим, разделяя их через "multipart/x-mixed-replace;boundary=ХХХХХХХ". Браузер обучен считать каждую картинку отдельным кадром и сам будет их сменять по мере поступления без дополнительных телодвижений со стороны клиента = тебе вообще не нужны ни скрипты, ни сокеты, ничего -- на странице будет только один тег <img>. Собственно, бОльшая часть морд простых веб-камер так и сделана. Поиск по этой строке (multipart...) даст тебе кучу ссылок, может и на Си там тоже что-то есть. Кстати, гипотетически, отдавать BMP мультикадровый, наверное, тоже можно, почему нет? https://pixelchinchilla.com/2017/05/diy-video-monitoring-system-part-iv-video-streaming-using-mjpeg/
     

    Вложения:

    • client.zip
      Размер файла:
      37 КБ
      Просмотров:
      242
    Igor68 нравится это.
  13. Igor68

    Igor68 Гуру

    Спасибо за отклик... извини... пришлось в магазин сбегать. Курю... точнее читаю!
     
  14. Igor68

    Igor68 Гуру

    Да! Вот только одно смущает:
    Код (C++):
    ...
                if(payload[0] == 'h' && payload[1] == 'i') // от клиента получен текст "hi"
                 {
                   char messag[] = "Hi client - ";
                   int message_size = (int) strlen(messag);
                   char out_data[128] = {0,};
                   memcpy(out_data + 2, messag, message_size); // копируем сообщение в массив "out_data" начиная со второго байта (первые два байта для опкода и длины тела)
                   char nom_client[5] = {0,};
                   sprintf(nom_client, "%d", client_fd); // номер клиента
                   int nom_client_size = (int) strlen(nom_client);
                   memcpy(out_data + 2 + message_size, nom_client, nom_client_size); // копируем номер клиента в массив "out_data" следом за сообщением

                   message_size += nom_client_size; // получаем длину тела сообщения

                   out_data[0] = 0x81;
                   out_data[1] = (char)message_size;

                   printf("\nSize out Msg: %d\n", message_size);
                 
                   if(send(client_fd, out_data, message_size + 2, 0) == -1) // отправка
                    {
                      warning_access_log("Error Hi.");
                      if(close(client_fd) == -1) warning_access_log("Error close client in WS_5."); // закрываем соединение с клиентом
                      pthread_exit(NULL);
                    }
                  }
    ...
     
    Тут нет упоминаний ответа сервера, который пропущен через Base64. Это при обмене. А вот при рукопожатии-соединении есть и SHA и Base64. При соединении всё это делал. А вот при работе применял только ключ в 4 байта, который получал от браузера
     
  15. DEgorov

    DEgorov Нерд

    Я бы просто взял любой из готовых вебсокет-серверов, которых на гитхабе тонны. Полагаю, что вот это, например https://github.com/allinurl/gwsocket (http://gwsocket.io/) вполне подойдёт -- утверждается, что у этого варианта нет зависимостей и собраться оно на той же MOXA вполне должно. Примеры есть тут: http://gwsocket.io/man Оно работает по сути как прокси, ты его запускаешь как демона и через пайпы или STDIN/STDOUT гоняешь данные. Проверил на дебиане 9 собирается за 10 секунд, даёт бинарник в 50 килобайт, работает.

    Реализовывать протоколы самому -- это дело, конечно, благородное, но неблагодарное. Ну это моё мнение...
     
  16. Igor68

    Igor68 Гуру

    Приветствую! Доброго времени суток! Протокол... как понимаю он вовсе не мой. Я наткнулся на это: https://istarik.ru/blog/programmirovanie/73.html
    и это: https://github.com/mrsin/k-lab/wiki/Передача-изображения-с-камеры-через-WebSocket
    Вот и решил отказаться от написания клиентов... каких-то клиентов. Что в QtCreator, что в Visual Studio и т.п. На каждой платформе есть браузер. Только с JS + HTML я не так дружен. И вот что пока вышло:
    snapshot1.png

    Сейчас происходит отрисовка закрашенных окружностей в программе-сервере прямо в ОЗУ и отсылка этих кадров-картинок прямо из ОЗУ в BMP формате клиенту JS на браузере... на страничке. Ну понятно сервер один поток, main, который рисует другой... и т.п.

    А механизм приёма (есть в архиве):
    Код (Javascript):
    function onMessage(evt){
        var ta = document.querySelector("#work");
        var blob = new Blob([evt.data], {type: "image/bmp"});
        ta.src = URL.createObjectURL(evt.data);
        }
    сформирован... и благодаря Тебе и указанным ссылкам.

    Собственно архив:
    websock5.zip

    Спасибо! Это всё многое меняет! Картинка онлайн на браузере... хоть игрушка, хоть прибор, хоть... Главное, что всякие оболочки не требуются.
    И... прошу разрешения на право задать вопрос по теме браузеров.
    Спасибо огромное!
     

    Вложения:

    • websock5.zip
      Размер файла:
      454,5 КБ
      Просмотров:
      448
  17. Igor68

    Igor68 Гуру

    Да так разумнее... но не всё можно прикрутить к MOXA. И отбраковано давно всё, что по душе, но непригодно для UC-7112-Lx-Llus или IA-240-Lx в плане применения. Потому и была ставка не на Питон (которого там нет), но есть Perl без библиотек (голый). А вот Си есть (кросскомпиляция на PC). И как в родном Debian такие вещи как aptitude и apt-get не проходят. Вот и мудрю.
     
    DEgorov нравится это.
  18. DEgorov

    DEgorov Нерд

    Рад, что получилось в итоге!
    Задавай, конечно.
     
  19. Igor68

    Igor68 Гуру

    Доброго времени суток!
    Я пока только изучаю этот самый WS... так что в файле app.js
    Код (Text):
    var wsUri = "ws://127.0.0.1:4321/";
    я применял локальный адрес 127.0.0.1 и соответственно сервер работает по нему и конечно страничка обращается к нему. В то же время на этом адресе и запускается сам сервер websock через bash скрипт start.sh... запускаю в консоли. Но на удалённом устройстве указываю вместо 127.0.0.1 указываю(редактирую) на реальный IP. Пока не разобрался как сделать иначе со стороны WS. И это только тесты... проверки так сказать. Основная цель очень быстрая смена картинок в реальном времени. Пока только этим занят, но далее буду решать по нормальному... как надо.
     
  20. Igor68

    Igor68 Гуру

    Доброго времени суток!
    Наверное надо сказать типа "Помогите"... но даже и не знаю...
    Имеем рабочий тест:
    snapshot2.png
    А именно на холсте (чёрная область и на остальное не смотреть) разноцветные кнопки... при клике мышкой на соответственной будет отрисована фигура фигура ссответствующая цвету кнопки. Там только круг и треугольник. Отрисовка происходит не в браузере, а на сервере и картинка транслируется в брвузер (страничку).
    Кнопки они "настоящие", а не просто квадратики и т.п. Смотрите в файле(main.c):
    Код (C++):
    buttonsINIT();
        buttonCREATE(10, 10, 80, 20, "test1\0", 255, 127, 127, 0,0,0, &test1);
        buttonCREATE(100, 10, 80, 20, "test2\0", 127, 255, 127, 0,0,0, &test2);
        buttonCREATE(190, 10, 80, 20, "test3\0", 127, 127, 255, 0,0,0, &test3);
        buttonCREATE(280, 10, 80, 20, "test4\0", 192, 192, 192, 0,0,0, &test4);
        buttonCREATE(370, 10, 80, 20, "test5\0", 192, 0, 0, 0,0,0, &test5);
        buttonCREATE(460, 10, 80, 20, "test6\0", 0, 192, 0, 0,0,0, &test6);
        buttonCREATE(550, 10, 80, 20, "test5\0", 0, 0, 192, 0,0,0, &test7);
    ...тут инициализируем структуру для кнопок, а затем создаём кнопки. Для каждой кнопки требуется:
    1) координаты;
    2) размер кнопки(ширина и высота;
    3) строка (будет отцентрована по ширине и высоте кнопки... должна быть завершена нулём);
    4) цвета кнопки и текста (в форме RGB);
    5) адрес функции, которая будет выполнена при клике мышкой.
    Сервер анализирует принятые от браузера параметры, перерисовывает кнопку(нажатие/отжатие) и выполняет соответствующую функцию.
    на страничке(нажатие на область холста):
    Код (Javascript):
    //клик
    function mouseclick()
    {
        if((WX > 0) && (WX < X) &&
        (WY > 0) && (WY < Y)) {
            Wx = WX;
            Wy = WY;
            Wk = 1;
        }
        //document.getElementById("mclick").innerHTML = "X=" + Wx + ";Y=" + Wy;
        msend = "mouse_X: " + Wx + "\nmouse_Y: " + Wy + "\n";
        wsApp.send(msend);
    }
    Вот архив:
    wsobj.zip
    Для работы в систему должна быть установлена библиотека SSL.. как правило везде установлена.
    Собственно вопрос к знатокам JavaScript:
    Имеем объявление адреса сервера
    Код (Javascript):
    var wsUri = "ws://127.0.0.1:4321/";
        //var wsUri = "ws://192.168.0.240:4321/";
    Как видите для испытай переназначаю адрес сервера в строчке скрипта. А хотелось бы, что бы было не зависимо от размещения сервера. То есть при получении страницы он бы был получен от самого сервера и вставлен в указанное место.
    Заранее Спасибо!
     

    Вложения:

    • wsobj.zip
      Размер файла:
      90,4 КБ
      Просмотров:
      380