"универсальный" TCP сервер на малине и ....(самодельный на Си)

Тема в разделе "Raspberry Pi", создана пользователем Igor68, 4 ноя 2016.

  1. AlexU

    AlexU Гуру

    Небольшое отступление: в Linux'е "всё" является файлами -- стандартные ввод и вывод тоже файлы. Приведённый пример с использованием 'cin' и 'cout' это всего лишь один из вариантов. В языке C используются 'scanf' и 'printf'. Но можно открыть как обычный файл и использовать методы 'read' и 'write', тогда ни каких переводов строк не нужно.
    Не понял, для чего экранировать байт '\n'. Тут суть в том, что 'cin' не вернёт строку до тех пор пока пользователь не нажмёт клавишу 'Enter', т.е. не введёт символ '\n'. Такая вот реализация у этого класса. Поэтому для нормальной работы примера echo-сервиса нужно отправлять строку завершённую символом '\n' -- например, 'qwerty\n". 'cin' считает эту строку, отбросит символ '\n' и в буфер попадёт только "qwerty".
    Но если Вы собираетесь отправлять команды, то эти команды как-нибудь нужно будет отделять друг от друга и символ '\n' не плохой вариант.

    PS: Тема организации сетевого взаимодействия в Linux или Windows интересная, но она уже жёвана пережёвана всеми, кому не лень... И есть уже готовые решения опробованные временем -- тот же xinetd в Linux, который позволяет создать сервер без необходимости вникания в то, что же такое сокеты и как с ними работать.
     
  2. Igor68

    Igor68 Гуру

    Похоже про обмен массивами я не говорил.... содержание каждого байта в которых произвольно... и команды из набора символов (<имя> <параметр1>....<параметрN> '\n') даже и не рассматривается.... к примеру Modbus RTU а не Modbus ASCII.....

    Так и сказали бы что это никому не надо. Напишите в сообщении - я удалю по возможности всё это.
    Извините!
     
    ИгорьК и arkadyf нравится это.
  3. Igor68

    Igor68 Гуру

    Пока прекращаю.... жду одобрения на продолжение... по результату предыдущего поста.
    Извините!!!
     
  4. AlexU

    AlexU Гуру

    Почему же не надо, было бы не интересно -- не подключился к разговору. Просто есть вопросы помногу раз разжёванные. В частности работа с сокетами и т.п. А есть вопросы обойдённые вниманием. В частности:
    В инете есть много статей на тему "вот, смотрите, создаём сокет, принимаем соединения, читаем... пишем...". А дальше... А дальше "кошка бросила котят, пусть....". Поэтому (по сугубо моему личному мнению, которое может быть ошибочным) часть про создание сокетов и организацию чтения/записи можно было упомянуть вскользь, а основной упор сделать на организации обмена данными. Какие приёмы применили для корректного обмена массивами произвольных данных?

    PS: по поводу Modbus, инет говорит что есть такая штука как Modbus TCP. Сталкивались?
     
  5. arkadyf

    arkadyf Гик

    не прекращайте ... лучше продолжить ... обязательно найдутся те, кому это пригодиться
     
  6. ИгорьК

    ИгорьК Гуру

    Пишите! Не надо сейчас - надо потом. Не сдавайтесь и живите по своим правилам.
     
  7. Igor68

    Igor68 Гуру

    Сталкивался! Использовал модуль ввода-вывода от ADVANTECH по ETHERNET. Но реализовал с аналогичными устройствами от ОВЕН по RS485 через UC-7112 plus/IA240-LX по Ethernet. Только Modbus TCP не стал - в пакет обмена добавил ряд служебных параметров кроме собственно данных... статус связи с устройством(ами), режим автоповторения запроса, интервал(задержка ответа) для каждого устройства. по схеме: "сеть Modbus RTU(RS485) с множеством устройств" <---> "Moxa(IA240/UC-7112LX plus)" <---> "сеть Ethernet" <---> "клинт(ы) на машинах Linux/Windows"
     
  8. Igor68

    Igor68 Гуру

    Спасибо! Пока готовлю связку: "сервер на малине" + "многопоточная DLL связи" + "тестовая EXE - пока консольная для отладки"
    Это не так быстро - надо по образу и подобию ранее реализованных сделать проекты... максимально понятных - с описанием (без комментариев уже было бы готово)
     
    Последнее редактирование: 6 ноя 2016
    ИгорьК нравится это.
  9. Igor68

    Igor68 Гуру

    5 - заготовка в Visual Studio (в моём случае VS2005 в Vindows XP). Создан мультипроект, что удобно для реализации DLL связи и нашей консольной тестовой программки. Фактически пока никаких действий не производится, кроме соединения с нашим сервером и поддержание связи.
    Пока проблема с загрузкой архива:( размер не превышает допустимого и расширение разрешено!
    Что это? Какие-нибудь ограничения?


    В связи с ограничением размера в 4.9 Мбайт, хотя размер архива 3.2 Мбайт всего мультипроекта... исходники DLL (настройка проекта по вышеупомянутой инструкции):
    temaDLL.h
    temaDLL.c

    Тестовая программа - консольное приложение в Win:
    test_console.h
    test_console.cpp

    результатом будут файлы, которые надо разместить в одной директории(из архива):
    bin.zip

    При запуске... вводе IP и порта бдет произведено соединение с нашим сервером на малине или иной Linux машине. Пока наша связка(exe+dll) только поддерживает связь с сервером... при этом 60 циклов будет только поддерживаться связь
    Код (Bash):
    igor@debian-i:/home/ext_projects/tema$ ./WorkServer -p 1234
    ---- opening tcp/ip  1234 ----
    -- CLIENT sock. 4 --
    ---- CLIENT START ----
    ---- CLIENT STOP ----
     
    статус соединения со стороны сервера на малине:
    Код (Bash):
    igor@debian-i:/home/ext_projects/tema$ netstat -nltpa
    (Not all processes could be identified, non-owned process info
    will not be shown, you would have to be root to see it all.)
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      -          
    tcp        0      0 0.0.0.0:139             0.0.0.0:*               LISTEN      -          
    tcp        0      0 0.0.0.0:19150           0.0.0.0:*               LISTEN      -          
    tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      -          
    tcp        0      0 0.0.0.0:1234            0.0.0.0:*               LISTEN      11518/WorkServer
    tcp        0      0 0.0.0.0:47730           0.0.0.0:*               LISTEN      -          
    tcp        0      0 192.168.8.10:53         0.0.0.0:*               LISTEN      -          
    tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN      -          
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -          
    tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      -          
    tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN      -          
    tcp        0      0 0.0.0.0:445             0.0.0.0:*               LISTEN      -          
    tcp        0      0 192.168.0.66:57605      64.233.161.200:443      ESTABLISHED 5188/iceweasel
    tcp        0      0 192.168.56.1:1234       192.168.56.101:1057     ESTABLISHED 11518/WorkServer
    tcp6       0      0 :::139                  :::*                    LISTEN      -          
    tcp6       0      0 :::19150                :::*                    LISTEN      -          
    tcp6       0      0 :::111                  :::*                    LISTEN      -          
    tcp6       0      0 :::80                   :::*                    LISTEN      -          
    tcp6       0      0 :::60368                :::*                    LISTEN      -          
    tcp6       0      0 fe80::e0a1:b8ff:fe28:53 :::*                    LISTEN      -          
    tcp6       0      0 :::22                   :::*                    LISTEN      -          
    tcp6       0      0 ::1:631                 :::*                    LISTEN      -          
    tcp6       0      0 ::1:5432                :::*                    LISTEN      -          
    tcp6       0      0 :::445                  :::*                    LISTEN      -          
    igor@debian-i:/home/ext_projects/tema$
    Обратите внимание на IP адрес = 192.168.56.1 - это мы отлаживаем/запускаем сервер для малины (но откомпилирован для Debian на ПК), а запускаем нашу "связку" EXE+DLL на виртуальном Win XP на том же ПК. Виртуальная машина очень удобна!!!!!!!:D

    консольная программа с загруженной DLL-кой
    scr1.jpg
    Далее следует позаботиться о правилах....... обмена.... отладки протокола..... и....

    На текущий момент подготавливается единый протокол для сервера (Linux) и клиента (DLL загружаемого модуля для программ Windows) таким образом, чтобы можно было "прикручивать" разные задачи в указанный код.
     

    Вложения:

    • temaDLL.h
      Размер файла:
      994 байт
      Просмотров:
      522
    • temaDLL.c
      Размер файла:
      5,8 КБ
      Просмотров:
      551
    • test_console.h
      Размер файла:
      207 байт
      Просмотров:
      608
    • test_console.cpp
      Размер файла:
      1,5 КБ
      Просмотров:
      508
    • bin.zip
      Размер файла:
      31,6 КБ
      Просмотров:
      137
    Последнее редактирование: 8 ноя 2016
    ИгорьК нравится это.
  10. Igor68

    Igor68 Гуру

    5.1 - "связка" для теста
    В данном случае код сервера не изменялся, но откомпилирован в самой малине. В архиве всё для малины... включая рабочий файл. Настоятельно рекомендую отлаживать всё на RAM-диске малины. Как его реализовать тут в темах рассматривалось.
    пробный тест для малины:
    tema.zip

    Изменённый исходник DLL-ки с приёмом и передачей:
    temaDLL.h
    temaDLL.c

    Тестовая консольная программа... точнее её исходники:
    test_console.h
    test_console.cpp

    Откомпилированные... готовые файлы для запуска в Windows:
    test_dll_exe.zip

    Dll-ка и EXE файл должны находиться в одной директории. В начале работы программа test_console.exe загружает temaDLL.dll. после чего производится запрос IP адреса и номера порта. При удачном соединении будет производиться запрос на чтение каждый цикл с отображением в консоли прочитанного в из сервера параметра. Как ранее говорилось в сервере кроме собственно потоков прослушивания и обработки каждого соединения в основном цикле MAIN выполняется тестовая функция.... специально для передачи клиенту.
    Код (C++):
    //тестовый модуль
    void    MainWork(void)
    {
        pthread_mutex_lock(&ServerMutex);
        if(test < 999.999)
            test += 11.1;
        else
            test = 0.0;
        (*(float*)(&wbufto[0])) = test;
        pthread_mutex_unlock(&ServerMutex);
    }
    Таким образом на Си реализованы:
    1 - сервер на малине или другой Linux машине;
    2 - DLL-ка работы с сервером и тестовая консольная программа.

    Зачем нужна DLL, когда можно всё сделать в обычной программе?! На первый взгляд лишнее... но... делать программы и каждый раз просто подключать одну и туже DLL удобнее. Особенно если несколько вариантов программы с применением одного и того же модуля. К примеру тестовая консоль и какое-нибудь оконное приложение не только C/C++, C#, но и Дельфи. В последнем я ни бум-бум, но DLL-ки для него делаю.
    Ну вроде и всё, но далее в продолжении прикручу вместо бестолкового кода работу с устройствами по I2C через этот самый сервер. Понятное дело всё, что тут показано сырой пример и требует доработки.
     

    Вложения:

    • tema.zip
      Размер файла:
      16,7 КБ
      Просмотров:
      148
    • temaDLL.h
      Размер файла:
      1,8 КБ
      Просмотров:
      495
    • temaDLL.c
      Размер файла:
      8,1 КБ
      Просмотров:
      535
    • test_console.h
      Размер файла:
      318 байт
      Просмотров:
      513
    • test_console.cpp
      Размер файла:
      2 КБ
      Просмотров:
      510
    • test_dll_exe.zip
      Размер файла:
      32,4 КБ
      Просмотров:
      140
    ИгорьК нравится это.
  11. Igor68

    Igor68 Гуру

    .....Наверное это баловство, но.... аналогично данной теме реализовано:
    1 - может кому интересно "рисование на BMP файле"... путём подачи серверу соответствующих команд.
    2 - "перерисованная" картинка в BMP файле на RAM диске отображается на WEB страничке

    При запуске в страничке через браузер копируется файл work.bmp в рам-диск (настоятельно рекомендовано) и запускается сервер работы с этим файлом.
    через PHP
    PHP:
    <?php
        $redicet = $_SERVER['HTTP_REFERER'];
        //
        $command = "./bmp_monitor start &";
        exec($command);
        //
        header ("Location: $redicet");
    ?>
    и соответственно BASH
    Код (Bash):
    #!/bin/bash


    par=$1

    case $par in
        "start")
            echo "Starting BMP Server"
            mkdir /home/httpd/ramdisk/bmp_monitor
            cp /home/httpd/games/BMPmonitor/work.bmp /home/httpd/ramdisk/bmp_monitor/work.bmp
            killall nfBMPserver
            ./nfBMPserver -f /home/httpd/ramdisk/bmp_monitor/work.bmp -p 8881 &
        ;;
        "stop")
            echo "Stop BMP Server"
            killall nfBMPserver
        ;;
        *)
            echo "{start|stop}"
        ;;
    esac
     
    Со стороны клиента - Debian в консоли производим соединение и вводим команду и параметры:
    Код (Bash):
    igor@debian-i:~/coding/diplom/src/testBmpClient$ ./testBmpClient
    ==== test ====

    Command error!
    -- input "help" for INFO --
    help
    ==========
    "help" -- current help screen
    "quit" -- for exit

    SRING MODE:
    "connect" -- connect to bmp_server
    "disconnect" -- disconnect from bmp_server

    "fileopen" -- open file for work (not creating)
    "fileclose" -- close opened file

    "setpixel" -- dawing one pixel in opened file (command "fileopen") <X and Y - coordinats>, <R,G,B - color>
    "line" -- dawing line in opened file (command "fileopen") <X1,Y1 and X2,Y2 - coordinats>, <R,G,B - color>
    "circle" -- dawing circle in opened file (command "fileopen") <X1 and X2 - coordinats>, <RADIUS - radius of circle>, <R,G,B - color>
    "circlefill" -- dawing filled circle in opened file (command "fileopen") <X1 and X2 - coordinats>, <RADIUS - radius of circle>, <R,G,B - color>
    "circlefill_fuzzy" -- dawing filled circle fuzzy in opened file (command "fileopen") <X1 and X2 - coordinats>, <RADIUS - radius of circle>, <R,G,B - color>
    "rect" -- dawing rectangle in opened file (command "fileopen") <X1,Y1 and X2,Y2 - coordinats>, <R,G,B - color>
    "rect_filled" -- dawing rectangle filled in opened file (command "fileopen") <X1,Y1 and X2,Y2 - coordinats>, <R,G,B - color>
    "triangle" -- dawing triangle in opened file (command "fileopen") <X1,Y1 and X2,Y2 and X3,Y3 - coordinats>, <R,G,B - color>

    BINARY MODE:
    "bconnect" -- connect to bmp_server
    "bdisconnect" -- disconnect from bmp_server

    "bfileopen" -- open file for work (not creating)
    "bfleclose" -- close opened file

    "bsetpixel" -- dawing one pixel in opened file (command "fileopen") <X and Y - coordinats>, <R,G,B - color>
    "bline" -- dawing line in opened file (command "fileopen") <X1,Y1 and X2,Y2 - coordinats>, <R,G,B - color>
    "bcircle" -- dawing circle in opened file (command "fileopen") <X1 and X2 - coordinats>, <RADIUS - radius of circle>, <R,G,B - color>
    "bcirclefill" -- dawing filled circle in opened file (command "fileopen") <X1 and X2 - coordinats>, <RADIUS - radius of circle>, <R,G,B - color>
    "bcirclefill_fuzzy" -- dawing filled circle fuzzy in opened file (command "fileopen") <X1 and X2 - coordinats>, <RADIUS - radius of circle>, <R,G,B - color>
    "brect" -- dawing rectangle in opened file (command "fileopen") <X1,Y1 and X2,Y2 - coordinats>, <R,G,B - color>
    "brect_filled" -- dawing rectangle filled in opened file (command "fileopen") <X1,Y1 and X2,Y2 - coordinats>, <R,G,B - color>
    "btriangle" -- dawing triangle in opened file (command "fileopen") <X1,Y1 and X2,Y2 and X3,Y3 - coordinats>, <R,G,B - color>

    ==========
    connect
    input IP address:192.168.0.240
    input IP port:8881
    IP port: 8881

    Command error!
    -- input "help" for INFO --
    circle
    X:200
    Y:200
    RADIUS:50
    R:255
    G:255
    B:0
    Ok
    triangle
    X1:10
    Y1:10
    X2:100
    Y2:100
    X3:200
    Y3:10
    R:255
    G:255
    B:255
    Ok

     
    Соответственно на странице браузера будет:
    bmp.jpg

    Изменение картинки могут производить одновременно несколько разных клиентов.
    Данный сервер следует перекомпилировать для малины. Для этого прежде следует изменить Makefile в проекте, а компиляцию производить на самой малине. Как показано:
    Код (Bash):
    #CC=terminal-gcc

    CC=gcc

    #PREFIXPATH=/usr/local/arm-linux/bin
    #CC=$(PREFIXPATH)/arm-linux-gcc
    Для работы потребуется установленный Aache+PHP на малине. Установка не отличается от установки на PC:
    apache_php_mysql.pdf
    В прилагаемом архиве
    bmp.zip
    находится проект сервера (откомпилирован для MOXA UC-7112-LX-Plus), клиент (откомпилирован для Debian ПК) и файлы относящиеся к WEB странице.
    Следует отметить про "файлы сокетов" - оптимальнее и нагляднее, чем рассматривалось ранее - взяты из примеров для Moxa, но пригодны как для PC так и для малины.
    Файлы для работы с BMP были сделаны по документации (доступно через поисковик).
    Методы отображения примитивов (точка, линия, прямоугольник и т.д.) повзаимствованы из старых исходников игры "ELITE"

    Ну вот для темы вроде всё. Про I2C... похоже не тут. Уж больно всё разрослось. Больше так мусорить не буду.
    Простите если что не так!!!!!
    С Глубоким уважением!
     

    Вложения:

    • bmp.zip
      Размер файла:
      300,7 КБ
      Просмотров:
      136
    • apache_php_mysql.pdf
      Размер файла:
      874,4 КБ
      Просмотров:
      617
    Последнее редактирование: 10 ноя 2016
    ИгорьК нравится это.
  12. Igor68

    Igor68 Гуру

    Доброго времени суток!
    Простите за беспокойство... но если есть необходимость принимать чёрно-белое видео в вашу программу в Windows от Raspberry Pi 3, оснащённого WEB камерой с разрешением 640x480 практически реального времени то на Raspberry следует запустить сервер обслуживания камеры и передачи данных, который в состоянии обслуживать несколько клиентов (картинку можно смотреть одновременно на нескольких компьютерах):
    camserver.zip
    для которого следует что запускается он скриптом start:

    Код (Bash):
    #!/bin/bash

    ./camserver -p 8998
     
    порт 8998 можете указать свой, но понятное дело он должен совпадать с портом клиента в вашей программе. Если следует сервер запускать в автозапуске то:
    ./camserver -p 8998 &

    В программе приёма (в ранее рассмотренном модуле dll) следует сделать изменения:
    Код (C++):
    /*
    ********************
    * для всех пакетов *
    ********************
    */

    //начальные адреса пакета
    #define _vtcp_szl               0x0000      //младший байт размера
    #define _vtype                  0x0004      //тип обращения - выбор режима (картинка и т.п.)
    #define _vcop                   0x0005      //код операции (чтение/запись)
    #define _vwidht                 0x0006      //ширина в случае работы с картинкой
    #define _vheight                0x0008      //высота в случае работы с картинкой
    #define _mtime                  0x000A      //маркер времени для синхронизации (2 байта)
    //байты с одресами 0x000С...0x000F резервируем для возможного дальнейшего расширения
    #define _vdaddr                 0x0010      //начало данных
    //команда для _vcop - собственно код операции
    #define    _vcop_rd                0x01        //чтение (от сервера клиенту) - в случае с картинкой байтовый массив картинки
    #define _vcop_wr                0x02        //запись (от клиента серверу) - в случае с картинкой параметры
    #define _vcop_rdwr              0x03        //чтение-запись

    /*
    ************************
    прямая передача картинки
    8 бит
    ************************
    */

    #define _vtype_scr8             0x01        //тип обращения - указывает, что от OpenCV картинка чёрно-белая 8 бит
    Тут у нас размер данных уже более чем 0xFFFF - то есть 640х480 = 307200 байт на картинку. Плюс размер шапки 16 байт. Соответственно и функция чтения из сокета должна принять параметр размера не 16 бит, а 32 бита:
    Код (C++):
    inline int cvReadSocket(int nSocket, BYTE *pBuffer)
    {
            //int     res                     = 1;
            int         iRC                     = 0;
            int         iReceiveStatus          = 0;
            int         iStillToReceive         = 4; //начальный размер получения минимальных данных
            int         iCount     = 0;
            int        sz    = 0;
            struct timeval     ReceiveTimeout;
            fd_set         fds;
            U8        flag            = 0;
            //fcntl(nSocket, F_SETFL, O_NONBLOCK);
            //fds = calloc(1, sizeof(fd_set));// fds;
            //int size = 0;
            while(iStillToReceive > 0)
            {
                     //установка величины таймаута
                    FD_ZERO(&fds);
                    FD_SET(nSocket, &fds);
                    ReceiveTimeout.tv_sec  = 0;
                    ReceiveTimeout.tv_usec = _SOCKET_TIMEOUT_;
                    iRC = select(nSocket + 1, &fds, NULL, NULL, &ReceiveTimeout);
                    //выход по таймауту
                    if(!iRC)
                return -1;
            //произошла какая то ошибка
                    if(iRC < 0)
                            return -2;
            //ошибка указания размера данных
                    if(iStillToReceive <= 0)
                            return -3;
                    //прием нескольких байт
            #if(_tcp_recv_deb == 1)
                printf("----read sock (recv) ----\r\n");
                #endif
                    iReceiveStatus = recv(nSocket, (char*)(pBuffer), iStillToReceive, 0);
                    if(iReceiveStatus >  0)
                    {
                        pBuffer += iReceiveStatus;
                        iStillToReceive -= iReceiveStatus;
                        iCount += iReceiveStatus;
                        if((iCount >= 4) && (flag == 0))
                        {
                            //iStillToReceive = (*(U16*)(pBuffer - iCount)) - iCount;
                            sz        = (*(U32*)(pBuffer - iCount));
                            iStillToReceive = sz - iCount;
                            flag = 0xFF;
                        }
                    }
            else if(iReceiveStatus == 0)
                return -1;
            else
                return -2;
            #if(_tcp_recv_deb == 1)
                printf("==iStillToReceive:%i iCount:%i==\r\n", iStillToReceive, iCount);
            #endif
            }
        //дополнительная проверка размера
        if(sz != iCount)
            return -3;
            //
            return iCount;
    }
    Поток обмена аналогично изменяется:
    Код (C++):
    void *  vclient_process(void * pr)
    {
        U8    txbuf[_vsize_buf];
        U8    rxbuf[_vsize_buf];
        U32    txsz = 0;
        U32 cntx, cnty, cntbyte;
        int    res;
        //
        while(vClientWork)
        {
            pthread_mutex_lock(&vClientMutex);
            //формирование запроса
            memset(&txbuf[0], 0, _vsize_buf);
            txbuf[_vtype]   = _vtype_scr8;
            txbuf[_vcop]    = _vcop_rd;
            txsz = 16;
            (*(U32*)(&txbuf[_vtcp_szl])) = txsz;
            //передача данных
            if(txsz > 0)
            {
                res = cvWriteSocket(vcclient.socket, &txbuf[0], txsz);
                switch(res)
                {
                    case -2:
                        vClientWork = 0;
                        break;
                    case 0:        //
                        break;
                    default:
                        break;
                }
            }
            //usleep(_vconn_sleep);
            res = cvReadSocket(vcclient.socket, &rxbuf[0]);
            //приём данных
            switch(res)
            {
                case 0:    //Ok
                    //countlive = setcntlive;
                    //mworkr(&rxbuf[0]);
                    break;
                case -1: //таймаут
                    #if(_deb == 1)
                        printf("TCP client recv. timeout..\r\n");
                    #endif
                    break;
                case -2: //какая-то ошибка сокета
                    #if(_deb == 1)
                        printf("TCP client resv. err?..\r\n");
                    #endif
                    goto mexit;
                case -3: //ошибка размера пакета
                    //передача сообщения о несоответствии
                    #if(_deb == 1)
                        printf("TCP client frame no correct..\r\n");
                    #endif
                    goto mexit; //отмена обработки запроса
                default: //нормально - данные приняты
                    //обработка ответа
                    tmark   = (*(U16*)(&rxbuf[_mtime]));
                    szx     = (*(U16*)(&rxbuf[_vwidht]));
                    szy     = (*(U16*)(&rxbuf[_vheight]));
                    vtype   = rxbuf[_vtype]; //тип принятых данных
                    cnty = 0;
                    cntbyte = 0;
                    while(cnty < szy)
                    {
                        cntx = 0;
                        while(cntx < szx)
                        {
                            vbuf[cntx][cnty] = rxbuf[_vdaddr + cntbyte];
                            cntbyte++;
                            cntx++;
                        }
                        cnty++;
                    }
                    break;
            }
            pthread_mutex_unlock(&vClientMutex);
            //
            usleep(_vconn_sleep); //премя "сна" - определит скорость смены кадров
        }
    mexit:    close(vcclient.socket);
        vClientWork = 0;
        pthread_mutex_unlock(&vClientMutex);
        //
        pthread_exit(0);
    }
    Буфер для приёма и передачи тоже имеют другой размер (ну это и понятно)
    Код (C++):
    #define _vsize_buf          (16 + (640 * 480))        //размер буфера для приёма и передачи по TCP
    ну и соответственно сам буфер:
    Код (C++):
    U8  wvbuf[640][480];
    Читаем мы данные для отображения не мешая потоку:
    Код (C++):

    //чтение значения видео
    I16 wRdCam(U8 * scr)
    {
      //int cntx,cnty;
      pthread_mutex_lock(&vClientMutex);
      rszx  = (int)(szx);
      rszy  = (int)(szy);
      rtmark  = (int)(tmark);
      memcpy(scr, &vbuf[0][0], rszx * rszy);
      pthread_mutex_unlock(&vClientMutex);
      return 0;
    }
     
    Данный код без проблем переносится в вышеуказанный. Стоит только произвести соответствие имён (функции чтения, мютекса, рабочего потока и другие мелочи).

    Простите за беспокойство!
    С Глубочайшим Уважением!
    (Пока нет новых идей в своей работе... а сам на длинном больничном... Если есть вопросы реализации для Windows помогу). В Debian (в QtCreator) всё готово!
    Ещё раз прошу прощения!
     

    Вложения:

    • camserver.zip
      Размер файла:
      65,9 КБ
      Просмотров:
      119
    Последнее редактирование: 18 дек 2016
    ИгорьК нравится это.
  13. Igor68

    Igor68 Гуру

    Простите это не продолжение темы... я не дома и наткнулся на некоторую информацию.
    Интересная, но может и не по теме:
    https://blackarch.ru/
    https://blackarch.ru/?s=wifi
    может кому-то и интересно, но оставил ссылку и для себя тоже.
    Ещё раз простите!
    С глубоким уважением!
     
  14. Igor68

    Igor68 Гуру

    Изменения как со стороны клиента, так и со стороны сервера.
    Ранее было так для приёма из сокета:
    Код (C++):

    memset(&rxbuf[0], 0, _tcp_size);
         res = ReadSocket(csock, &rxbuf[0]);
         switch(res)
         {
           case 0:   //Null
             break;
           case -1:        //таймаут
             break;
           case -2:        //какая-то ошибка сокета
             goto mexit;
           case -3:        //ошибка размера пакета
             break;
           default:        //нормально - данные приняты
             countlive = _time_life;
             break;
         }
     
    Далее изменил на:
    Код (C++):

    memset(&rxbuf[0], 0, _tcp_size);
         res = ReadSocket(csock, &rxbuf[0]);
         switch(res)
         {
           case 0:   //Null
           case -1:        //таймаут
           case -2:        //какая-то ошибка сокета
             goto mexit;
           case -3:        //ошибка размера пакета
             break;
           default:        //нормально - данные приняты
             countlive = _time_life;
             break;
         }
     
    Аналогично поступил и с передачей:
    Код (C++):

    if(txsz > 0)
         {
           //pthread_mutex_unlock(&ServerMutex);
           res = WriteSocket(csock, &txbuf[0], txsz);
           switch(res)
           {
             case 0:
             case -1:     //таймаут
             case -2:     //какая-то ошибка сокета
               goto mexit;
             default:     //нормально - данные переданы
               break;
           }
         }
     
    В данном случае нормальное вторичное подключение к серверу в случае прекращения соединения. Не стало "длительных подвисаний" при повторном соединении.
     
    Последнее редактирование: 25 янв 2017
    arkadyf нравится это.