Перейти к содержанию
Fire Monkey от А до Я

Евгений Корепов

Пользователи
  • Постов

    738
  • Зарегистрирован

  • Посещение

  • Победитель дней

    100

Активность репутации

  1. Like
    Евгений Корепов получил реакцию от slav_z в информация о версии консольного приложения   
    https://unix.stackexchange.com/questions/58846/viewing-linux-library-executable-version-info
  2. Like
    Евгений Корепов получил реакцию от Ingalime в [РЕШЕНО]: Как отловить кнопки пульта ДУ   
    Друзья, вы будете смеяться - Эмбаркадера наконец то обратила внимание на заявку по этой проблеме. Правда в стиле моя-твоя непонимай ))) 
    https://quality.embarcadero.com/browse/RSP-16910
  3. Like
    Евгений Корепов получил реакцию от Ingalime в информация о версии консольного приложения   
    В Линуксе просто нет никаких стандартов для размещения версии внутри бинарника. Ембаркадера об этом не в курсе, но по привычке воткнула пустую заглушку ))) Забейте, и просто делайте свою константу с версией.
  4. Like
    Евгений Корепов получил реакцию от AngryOwl в IdTCPClient, IdTCPServer и соеденение   
    Тут все просто - нужно ждать. Ваш код работает корректно только в идеальных условиях. Но если вторая сторона не ответила мгновенно, то вы уже ничего не получите.
    Перед отправкой/получением вам надо проверить наличие соединения функцией FTCPClient.IOHandler.CheckForDisconnect()  - при отсутствии соединения она сгенерит исключение:
    try FTCPClient.IOHandler.CheckForDisconnect(); except on E: EIdException do begin LogError('TUTM5StreamProtocol.Run CheckForDisconnect ERROR ' + E.Message); Reconnect(); end; end; Читать с ожиданием данных можно несколькими способами:
    1. Задавать FTCPClient.IOHandler.ReadTimeout в надежде что в отведенное время что то придет.
    2. Использовать FTCPClient.IOHandler.ReadLnWait() для чтения строки.
    3. Или обрабатывать проверять наличие данных и читать по мере их поступления:
    if FTCPClient.IOHandler.CheckForDataOnSource(FConnectParams.Timeouts.TCPReadTimeout) then читаем....  
  5. Like
    Евгений Корепов получил реакцию от slav_z в Запуск демона на Linux   
    Вот просто идеальная статья по запуску демона под Linux http://blog.paolorossi.net/2017/09/04/building-a-real-linux-daemon-with-delphi-part-2/ 
    Помимо объяснения механизма fork с отличными примерами,  есть куча дополнительной наиполезнейшей инфы.
  6. Like
    Евгений Корепов получил реакцию от #WAMACO в IdTCPClient, IdTCPServer и соеденение   
    Тут все просто - нужно ждать. Ваш код работает корректно только в идеальных условиях. Но если вторая сторона не ответила мгновенно, то вы уже ничего не получите.
    Перед отправкой/получением вам надо проверить наличие соединения функцией FTCPClient.IOHandler.CheckForDisconnect()  - при отсутствии соединения она сгенерит исключение:
    try FTCPClient.IOHandler.CheckForDisconnect(); except on E: EIdException do begin LogError('TUTM5StreamProtocol.Run CheckForDisconnect ERROR ' + E.Message); Reconnect(); end; end; Читать с ожиданием данных можно несколькими способами:
    1. Задавать FTCPClient.IOHandler.ReadTimeout в надежде что в отведенное время что то придет.
    2. Использовать FTCPClient.IOHandler.ReadLnWait() для чтения строки.
    3. Или обрабатывать проверять наличие данных и читать по мере их поступления:
    if FTCPClient.IOHandler.CheckForDataOnSource(FConnectParams.Timeouts.TCPReadTimeout) then читаем....  
  7. Like
    Евгений Корепов отреагировална krapotkin в Почему не очищается ImageList ?   
    главное не говорить, что за ошибка )
    а пока не говорите, могу только поинтересоваться почему Form1.ImageList1 ?
  8. Like
    Евгений Корепов получил реакцию от Ingalime в Обновление клиента по событию   
    Запоминайте в php последний номер добавленной записи (id), добавьте в api метод вроде GetLastRecordsIDs, который будет возвращать все ID нужных таблиц. Клиент пусть долбится в этот метод раз в N секунд и сверяет свои последние ID с ID сервера, при не совпадении - запрос новых данных.
    В php хранить последние идешники можно как угодно - файл, сессия, ну или memcache чтоб уж совсем быстро было. Я бы хранил в сессии, и сессию сделал в memcached.
  9. Like
    Евгений Корепов получил реакцию от Ingalime в export and save the contents   
    Use jsPDF https://github.com/MrRio/jsPDF
    Example https://www.codexworld.com/convert-html-to-pdf-using-javascript-jspdf/
  10. Like
    Евгений Корепов отреагировална krapotkin в Поток в Firemonkey Android для скачивания TXT   
    e THttpClient есть свойства в которых есть слово Timeout. Их можно установить, и запрос будет вываливаться по Exception
    поэтому нужно добавить обработку Try Except  вместо или дополнительно к Try Finally
    в обработчике Except можно куда-то записывать результат или так же через синхронизацию например выводить сообщение на экран
  11. Like
    Евгений Корепов получил реакцию от GASCHE в как ускорить обработку данных   
    Как верно подметил Дмитрий - знание SQL наше все.
    Вот к примеру я создал тестовую таблицу и наполнил ее тестовыми данными:
    CREATE TABLE `test001` ( `id` int(11) NOT NULL AUTO_INCREMENT, `TimeFrom` datetime DEFAULT NULL, `InA` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8; INSERT INTO `test001` VALUES ('1', '2020-05-17 16:14:36', '1'); INSERT INTO `test001` VALUES ('2', '2020-05-17 16:12:56', '2'); INSERT INTO `test001` VALUES ('3', '2020-05-17 16:12:56', '3'); INSERT INTO `test001` VALUES ('4', '2020-05-17 17:12:56', '4'); INSERT INTO `test001` VALUES ('5', '2020-05-17 17:12:56', '5'); INSERT INTO `test001` VALUES ('6', '2020-05-17 17:12:56', '6'); INSERT INTO `test001` VALUES ('7', '2020-05-17 18:12:56', '7'); INSERT INTO `test001` VALUES ('8', '2020-05-17 18:12:56', '8'); INSERT INTO `test001` VALUES ('9', '2020-05-17 18:12:56', '9'); INSERT INTO `test001` VALUES ('10', '2020-05-17 19:12:56', '10'); INSERT INTO `test001` VALUES ('11', '2020-05-17 19:12:56', '11'); INSERT INTO `test001` VALUES ('12', '2020-05-17 19:12:56', '12'); INSERT INTO `test001` VALUES ('13', '2020-05-17 20:12:56', '13'); INSERT INTO `test001` VALUES ('14', '2020-05-17 20:12:56', '14'); INSERT INTO `test001` VALUES ('15', '2020-05-17 20:12:56', '15'); INSERT INTO `test001` VALUES ('16', '2020-05-17 21:12:56', '16'); INSERT INTO `test001` VALUES ('17', '2020-05-17 21:12:56', '17'); INSERT INTO `test001` VALUES ('18', '2020-05-17 21:12:56', '18'); Для получения почасовых сумм по полю InA мне достаточно очень простого запроса:
    SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600), SUM(test001.InA) as SumInA FROM test001 GROUP BY FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600 Результат запроса будет выглядеть вот так:
    2020-05-17 16:00:00 6 2020-05-17 17:00:00 15 2020-05-17 18:00:00 24 2020-05-17 19:00:00 33 2020-05-17 20:00:00 42 2020-05-17 21:00:00 51 Скорость выдачи результата будет большой - при миллионах записей в исходной таблице дело нескольких секунд или десятков секунд (зависит от железа сервера). 
    Но это все равно медленно, потому что на каждую запись таблицы будет производится вычисление "FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600" - деление, округление и умножение.
    Если это разовая выборка - проблем нет. Но если вам нужно регулярно дергать из таблицы данные, то лучше добавить в таблицу поле TimeFromHour, в которое сразу записывать значение  FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600. Это можно сделать руками или триггером при вставке. Добавить Индекс по полю TimeFromHour и в запросе тоже группировать (GROUP BY) по этому полю:
    ALTER TABLE `test001` ADD INDEX `Index-TimeFromHour` (`TimeFromHour`) USING BTREE ; Тогда вы получите максимально возможное быстродействие.
    Если нужно результат вставить в другую таблицу, то используйте запрос вроде такого:
    INSERT INTO test_sum (TimeFrom, SumInA) ( SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600), SUM(test001.InA) as SumInA FROM test001 GROUP BY FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600 )  
  12. Like
    Евгений Корепов получил реакцию от Ingalime в как ускорить обработку данных   
    Как верно подметил Дмитрий - знание SQL наше все.
    Вот к примеру я создал тестовую таблицу и наполнил ее тестовыми данными:
    CREATE TABLE `test001` ( `id` int(11) NOT NULL AUTO_INCREMENT, `TimeFrom` datetime DEFAULT NULL, `InA` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8; INSERT INTO `test001` VALUES ('1', '2020-05-17 16:14:36', '1'); INSERT INTO `test001` VALUES ('2', '2020-05-17 16:12:56', '2'); INSERT INTO `test001` VALUES ('3', '2020-05-17 16:12:56', '3'); INSERT INTO `test001` VALUES ('4', '2020-05-17 17:12:56', '4'); INSERT INTO `test001` VALUES ('5', '2020-05-17 17:12:56', '5'); INSERT INTO `test001` VALUES ('6', '2020-05-17 17:12:56', '6'); INSERT INTO `test001` VALUES ('7', '2020-05-17 18:12:56', '7'); INSERT INTO `test001` VALUES ('8', '2020-05-17 18:12:56', '8'); INSERT INTO `test001` VALUES ('9', '2020-05-17 18:12:56', '9'); INSERT INTO `test001` VALUES ('10', '2020-05-17 19:12:56', '10'); INSERT INTO `test001` VALUES ('11', '2020-05-17 19:12:56', '11'); INSERT INTO `test001` VALUES ('12', '2020-05-17 19:12:56', '12'); INSERT INTO `test001` VALUES ('13', '2020-05-17 20:12:56', '13'); INSERT INTO `test001` VALUES ('14', '2020-05-17 20:12:56', '14'); INSERT INTO `test001` VALUES ('15', '2020-05-17 20:12:56', '15'); INSERT INTO `test001` VALUES ('16', '2020-05-17 21:12:56', '16'); INSERT INTO `test001` VALUES ('17', '2020-05-17 21:12:56', '17'); INSERT INTO `test001` VALUES ('18', '2020-05-17 21:12:56', '18'); Для получения почасовых сумм по полю InA мне достаточно очень простого запроса:
    SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600), SUM(test001.InA) as SumInA FROM test001 GROUP BY FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600 Результат запроса будет выглядеть вот так:
    2020-05-17 16:00:00 6 2020-05-17 17:00:00 15 2020-05-17 18:00:00 24 2020-05-17 19:00:00 33 2020-05-17 20:00:00 42 2020-05-17 21:00:00 51 Скорость выдачи результата будет большой - при миллионах записей в исходной таблице дело нескольких секунд или десятков секунд (зависит от железа сервера). 
    Но это все равно медленно, потому что на каждую запись таблицы будет производится вычисление "FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600" - деление, округление и умножение.
    Если это разовая выборка - проблем нет. Но если вам нужно регулярно дергать из таблицы данные, то лучше добавить в таблицу поле TimeFromHour, в которое сразу записывать значение  FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600. Это можно сделать руками или триггером при вставке. Добавить Индекс по полю TimeFromHour и в запросе тоже группировать (GROUP BY) по этому полю:
    ALTER TABLE `test001` ADD INDEX `Index-TimeFromHour` (`TimeFromHour`) USING BTREE ; Тогда вы получите максимально возможное быстродействие.
    Если нужно результат вставить в другую таблицу, то используйте запрос вроде такого:
    INSERT INTO test_sum (TimeFrom, SumInA) ( SELECT FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600), SUM(test001.InA) as SumInA FROM test001 GROUP BY FLOOR(UNIX_TIMESTAMP(test001.TimeFrom) / 3600) * 3600 )  
  13. Like
    Евгений Корепов получил реакцию от Ingalime в TThread.GetTickCount64 хелпер для TThread   
    По умолчанию в TThread классовая функция GetTickCount имеет тип Cardinal, соответственно если приложение рассчитано на долговременную работу, то через 40 дней результат этой функции или уложит приложение (если отключена защита от переполнения) или превратит приложение в тыкву (если на этом завязана какая то логика).
    Для своего проекта написал хелпер для класса TThread, вдруг кому пригодится. Тестил на win10 x64 и linux x64. 
    unit UnitTThreadHelper; interface uses {$IFDEF MSWINDOWS} Winapi.Windows, {$ENDIF MSWINDOWS} {$IFDEF POSIX} Posix.SysTypes, {$IFDEF MACOS} Macapi.CoreServices, {$ENDIF MACOS} {$IFDEF ANDROID} Posix.Fcntl, {$ENDIF ANDROID} {$IFDEF LINUX} Posix.Time, {$ENDIF LINUX} {$ENDIF POSIX} System.Classes; type TThreadHelper = class helper for TThread class function GetTickCount64 : Int64; static; end; implementation class function TThreadHelper.GetTickCount64 : Int64; {$IF Defined(MSWINDOWS)} begin Result := Winapi.Windows.GetTickCount64; end; {$ELSEIF Defined(MACOS)} begin Result := AbsoluteToNanoseconds(mach_absolute_time) div 1000000; end; {$ELSEIF Defined(POSIX)} var res: timespec; begin clock_gettime(CLOCK_MONOTONIC, @res); Result := (Int64(1000000000) * res.tv_sec + res.tv_nsec) div 1000000; end; {$ELSE OTHERPLATFORM} {$MESSAGE Fatal 'Method not implemented for Platform'} {$ENDIF OTHERPLATFORM} end. При попытке запуска на win x32 упадет  - не используйте или проверяйте битность:
    if CheckWin32Version(6, 0) then begin GetTickCount64; end else begin GetTickCount; end;  
  14. Like
    Евгений Корепов отреагировална krapotkin в com-порт FireMonkey   
    вполне можно без компонентов пользоваться просто WinApi
    portNum='\\.\COM28'; CommHandle:= CreateFile(portNum,GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,0); ссылка
  15. Like
    Евгений Корепов отреагировална Slym в multicast udp   
    https://habr.com/ru/post/141021/
    ключевой момент "Подключение к группе"
  16. Like
    Евгений Корепов отреагировална Slym в multicast udp   
    А в инде все готово...
    procedure TForm1.FormCreate(Sender: TObject); begin   IdUDPServer1.ReuseSocket:=TIdReuseSocket.rsTrue;   IdUDPServer1.DefaultPort:=9898;   IdUDPServer1.Active:=true; end; procedure TForm1.IdUDPServer1AfterBind(Sender: TObject); begin   IdUDPServer1.Bindings[0].AddMulticastMembership('224.0.0.50'); end;  
  17. Like
    Евгений Корепов получил реакцию от slav_z в Delphi FastCGI клиент для php-fpm и подобного   
    Класс для работы с FastCGI серверами, такими как php-fpm.
    Для тех кто не в теме : веб-сервер, к примеру nginx, получает запросы и отправляет их на исполнение FastCGI серверу, к примеру php-fpm, php-fpm получает имя скрипта, параметры, выполняет все и возвращает результат в nginx, который в свою очередь возвращает этот результат запросившему клиенту.
    С помощью класса вы можете так же, выполнять php скрипты на локальном или удаленном сервере.
    Исходники https://github.com/EvgeniyKorepov/FastCGIClient
    Пример delphi
    var FFastCGI : TFastCGI; ... procedure TFormMain.FormCreate(Sender: TObject); var AHost : String; APort : Word; AScriptFileName, ARequest, AContent : String; begin AHost := '10.0.0.4'; APort := 9000; FFastCGI := TFastCGI.Create(AHost, APort); FFastCGI.KeepAlive := True; AScriptFileName := '/opt/xxx.php'; ARequest := 'request=1234567890'; if FFastCGI.Get(AScriptFileName, ARequest, AContent) then Memo.Text := AContent else Memo.Text := FFastCGI.StatusCode.ToString + ' ' + FFastCGI.StatusText; end; пример php 
    <?php header('Content-Type: text/html; charset=utf-8'); if (isset($_REQUEST["request"])) if ($_REQUEST["request"] == "1234567890") { header("Status: 200"); echo 'OK'; } else { http_response_code(400); echo "ERROR"; }  
  18. Like
    Евгений Корепов получил реакцию от mazayhin в Создание сервиса (демона) нового стиля для Linux   
    В прошлой теме я показал как делать демонов старой школы - серьезных и самодостаточных. Но это все в прошлом. Теперь существуют системы управления процессами, где все намного, намного проще.
    Исходники тут https://github.com/EvgeniyKorepov/LinuxDaemonNewStyle
    Заметьте, теперь никаких потоков, все элементарно, systemd сделает всю работу за нас.
    Половина кода - разбор параметров командной строки. Вторая половина - бесконечный цикл, ожидающий сигналов от экземпляра класса демона нового стиля . Код самого класса сократился на треть.
    Если запустите приложения в консоли - будет самое обычное приложение, которые умрет при закрытии консоли. Запуск в качестве бессмертного демона - через systemd, причем он сможет автоматически перезапускать вашего демона при крахе. Эти параметры задаются в текстовом файле /etc/systemd/system/DaemonNewStyleTest.service
    program DaemonNewStyleTest; {$APPTYPE CONSOLE} uses System.SysUtils, System.IOUtils, System.SyncObjs, Posix.Stdlib, Posix.SysStat, Posix.SysTypes, Posix.Unistd, Posix.Signal, Posix.Fcntl, Posix.Syslog in 'Posix.Syslog.pas', UnitDaemonNewStyle in 'UnitDaemonNewStyle.pas'; var AEvent : TEventType; begin if ParamCount = 0 then begin syslog(LOG_ERR, 'No parameters'); ExitCode := EXIT_FAILURE; exit; end; if ParamStr(1).ToLower.Equals('stop') then begin if Daemon.Stop(30) then ExitCode := EXIT_SUCCESS else ExitCode := EXIT_FAILURE; exit; end; if ParamStr(1).ToLower.Equals('reload') then begin if Daemon.Reload() then ExitCode := EXIT_SUCCESS else ExitCode := EXIT_FAILURE; exit; end; if not ParamStr(1).ToLower.Equals('start') then begin syslog(LOG_ERR, 'Unknow parameters'); ExitCode := EXIT_FAILURE; exit; end; syslog(LOG_NOTICE, 'main START'); while Daemon.IsRunning do begin syslog(LOG_NOTICE, 'main LOOP'); Daemon.Execute(AEvent); if AEvent <> TEventType.None then syslog(LOG_NOTICE, 'main Daemon receive signal'); case AEvent of TEventType.Start : begin syslog(LOG_NOTICE, 'main Event START'); end; TEventType.Reload : begin // Reload config syslog(LOG_NOTICE, 'main Event RELOAD'); end; TEventType.Stop : begin syslog(LOG_NOTICE, 'main Event STOP'); ExitCode := EXIT_SUCCESS; Sleep(10); // simulate destroy delay break; end; end; Sleep(1000); end; end. systemctl start DaemonNewStyleTest.service systemctl reload DaemonNewStyleTest.service systemctl stop DaemonNewStyleTest.service  
  19. Like
    Евгений Корепов получил реакцию от #WAMACO в Delphi FastCGI клиент для php-fpm и подобного   
    Класс для работы с FastCGI серверами, такими как php-fpm.
    Для тех кто не в теме : веб-сервер, к примеру nginx, получает запросы и отправляет их на исполнение FastCGI серверу, к примеру php-fpm, php-fpm получает имя скрипта, параметры, выполняет все и возвращает результат в nginx, который в свою очередь возвращает этот результат запросившему клиенту.
    С помощью класса вы можете так же, выполнять php скрипты на локальном или удаленном сервере.
    Исходники https://github.com/EvgeniyKorepov/FastCGIClient
    Пример delphi
    var FFastCGI : TFastCGI; ... procedure TFormMain.FormCreate(Sender: TObject); var AHost : String; APort : Word; AScriptFileName, ARequest, AContent : String; begin AHost := '10.0.0.4'; APort := 9000; FFastCGI := TFastCGI.Create(AHost, APort); FFastCGI.KeepAlive := True; AScriptFileName := '/opt/xxx.php'; ARequest := 'request=1234567890'; if FFastCGI.Get(AScriptFileName, ARequest, AContent) then Memo.Text := AContent else Memo.Text := FFastCGI.StatusCode.ToString + ' ' + FFastCGI.StatusText; end; пример php 
    <?php header('Content-Type: text/html; charset=utf-8'); if (isset($_REQUEST["request"])) if ($_REQUEST["request"] == "1234567890") { header("Status: 200"); echo 'OK'; } else { http_response_code(400); echo "ERROR"; }  
  20. Like
    Евгений Корепов получил реакцию от Tumaso в Создание сервиса (демона) нового стиля для Linux   
    В прошлой теме я показал как делать демонов старой школы - серьезных и самодостаточных. Но это все в прошлом. Теперь существуют системы управления процессами, где все намного, намного проще.
    Исходники тут https://github.com/EvgeniyKorepov/LinuxDaemonNewStyle
    Заметьте, теперь никаких потоков, все элементарно, systemd сделает всю работу за нас.
    Половина кода - разбор параметров командной строки. Вторая половина - бесконечный цикл, ожидающий сигналов от экземпляра класса демона нового стиля . Код самого класса сократился на треть.
    Если запустите приложения в консоли - будет самое обычное приложение, которые умрет при закрытии консоли. Запуск в качестве бессмертного демона - через systemd, причем он сможет автоматически перезапускать вашего демона при крахе. Эти параметры задаются в текстовом файле /etc/systemd/system/DaemonNewStyleTest.service
    program DaemonNewStyleTest; {$APPTYPE CONSOLE} uses System.SysUtils, System.IOUtils, System.SyncObjs, Posix.Stdlib, Posix.SysStat, Posix.SysTypes, Posix.Unistd, Posix.Signal, Posix.Fcntl, Posix.Syslog in 'Posix.Syslog.pas', UnitDaemonNewStyle in 'UnitDaemonNewStyle.pas'; var AEvent : TEventType; begin if ParamCount = 0 then begin syslog(LOG_ERR, 'No parameters'); ExitCode := EXIT_FAILURE; exit; end; if ParamStr(1).ToLower.Equals('stop') then begin if Daemon.Stop(30) then ExitCode := EXIT_SUCCESS else ExitCode := EXIT_FAILURE; exit; end; if ParamStr(1).ToLower.Equals('reload') then begin if Daemon.Reload() then ExitCode := EXIT_SUCCESS else ExitCode := EXIT_FAILURE; exit; end; if not ParamStr(1).ToLower.Equals('start') then begin syslog(LOG_ERR, 'Unknow parameters'); ExitCode := EXIT_FAILURE; exit; end; syslog(LOG_NOTICE, 'main START'); while Daemon.IsRunning do begin syslog(LOG_NOTICE, 'main LOOP'); Daemon.Execute(AEvent); if AEvent <> TEventType.None then syslog(LOG_NOTICE, 'main Daemon receive signal'); case AEvent of TEventType.Start : begin syslog(LOG_NOTICE, 'main Event START'); end; TEventType.Reload : begin // Reload config syslog(LOG_NOTICE, 'main Event RELOAD'); end; TEventType.Stop : begin syslog(LOG_NOTICE, 'main Event STOP'); ExitCode := EXIT_SUCCESS; Sleep(10); // simulate destroy delay break; end; end; Sleep(1000); end; end. systemctl start DaemonNewStyleTest.service systemctl reload DaemonNewStyleTest.service systemctl stop DaemonNewStyleTest.service  
  21. Like
    Евгений Корепов получил реакцию от mazayhin в Требуется приложение на на все смартфоны   
    Вам проще адаптировать сайт https://gector-spb.ru/ для мобильных браузеров. Наймите верстальшика за доширак - обойдется дешевле и по времени гораздо быстрее.
  22. Like
    Евгений Корепов получил реакцию от Tumaso в Создание сервиса (демона) в Linux   
    Я написал класс для демонизации приложения в linux. Класс форкает процесс, обрабатывает поступающие сигналы и передает их в основной поток через потокобезопасную очередь.
    Исходники https://github.com/EvgeniyKorepov/LinuxDaemon
    Для использования просто подключите модуль UnitDaemon в свое консольное приложение:
    program DaemonTest; {$APPTYPE CONSOLE} uses System.SysUtils, System.IOUtils, System.SyncObjs, Posix.Stdlib, Posix.SysStat, Posix.SysTypes, Posix.Unistd, Posix.Signal, Posix.Fcntl, Posix.Syslog in 'Posix.Syslog.pas', UnitDaemon in 'UnitDaemon.pas'; var AEventType : TEventType; begin syslog(LOG_NOTICE, 'main START'); while True do begin syslog(LOG_NOTICE, 'main LOOP'); if UnitDaemon.QueueEvent.PopItem(AEventType) = System.SyncObjs.TWaitResult.wrSignaled then begin syslog(LOG_NOTICE, 'main UnitDaemon.QueueEvent.PopItem'); case AEventType of TEventType.StopProcess : begin syslog(LOG_NOTICE, 'main Event StopProcess'); ExitCode := EXIT_SUCCESS; exit; end; TEventType.Start : begin syslog(LOG_NOTICE, 'main Event START'); end; TEventType.Reload : begin // Reload config syslog(LOG_NOTICE, 'main Event RELOAD'); end; TEventType.Stop : begin syslog(LOG_NOTICE, 'main Event STOP'); ExitCode := EXIT_SUCCESS; exit; end; end; end; Sleep(50); end; end. Так же поддерживается systemd - для этого положите  DaemonTest.service в /etc/systemd/system/ и используйте :
    systemctl start DaemonTest.service systemctl reload DaemonTest.service systemctl stop DaemonTest.service  
  23. Like
    Евгений Корепов отреагировална Slym в HTTP отправка Image на сервер в формате stream   
    обычно ничего не получается сопровождается текстом: 'Ошибка сети: '+E.Message или lResponse.StatusCode
    Почувствуй разницу:
    у мена ошибка с текстом " " в строке n, снифаю - все уходит но не сервер не сохраняет, помогите мне,
    ой все! ничего не работает! вот мой высер, доделайте за меня... ну че, слабаки! не могете?
  24. Like
    Евгений Корепов получил реакцию от #WAMACO в Запуск демона на Linux   
    Вот просто идеальная статья по запуску демона под Linux http://blog.paolorossi.net/2017/09/04/building-a-real-linux-daemon-with-delphi-part-2/ 
    Помимо объяснения механизма fork с отличными примерами,  есть куча дополнительной наиполезнейшей инфы.
  25. Like
    Евгений Корепов отреагировална ddr 2 в TThreadedQueue некорректное "ожидание" данных очереди   
    Добрый день!
    Заметил неприятный эффект(баг, особенность либо моё недопонимание чего либо). Через некоторое непродолжительно время работы PopItem( в версии возвращающей TWaitResult) перестаёт ожидать данные из очереди, и перестаёт  "усыплять" на(до) TThreadedQueue.FPopTimeout мсек,  поток из которого была вызвана, а возвращает wrTimeout без ожидания(менее 100 тактов). Ниже тестовый код, который демонстрирует этот эффект.
    Описание теста: основной поток, создаёт поток с условным названием FirstDepthThread, который:
     -запускает MaxThread(константа)+1 потоков( по умолчанию их 10) с условными названиями SecondDepthThread_X ;
    - c интервалом в 2-5 секунды в каждую из очередей записывается константный идентификатор. Кол-во очередей =MaxThread+1(в каждом из  потоков SecondDepthThread_X есть поле с очередью) .
    Функционал потоков SecondDepthThread_X - ждать данных извлекать их  из очереди. 
    В Procedure TSecondDepthThread.Execute есть 2-а условия( помечены в тексте, как {жучок 1} и {жучок 2}), которые в моём понимании никогда не должны выполняться, но...выполняются. Понимание, как обойти этот эффект есть, но очень хочется разобраться, что не так с указанной реализацией? Буду рад мнениям.
    Условия тестирования: Delphi 10.3.1., W10.1903. Так же рекомендуется попробовать разные значения MaxThread( при MaxThread=2, эффект может и не наступить,при MaxThread= 9, на 3-х разные cpu Intel эффект наступает через ,5-5 секунд, на стареньком AMD FX-8300 лишь через 2-10 минут. при MaxThread=14, AMDешный cpu так же "сдаётся" за несколько секунд). В отладчике смотрим окно Events. Если без отладчика, то в виндовом диспетчере задач, как только загрузка процессора у данного процесс подскочила от 0 к 100%, значит эффект достигнут.
    unit UThreadedQueue; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,System.Generics.Collections; Const MaxThread=9; type TSecondDepthThread=class(TThread) Protected FThreadNomber:integer; FError:boolean; Procedure Execute;override; Public TickSending:Cardinal; TickInterval:Cardinal; SendingDataQuery:TThreadedQueue<TBytes>; constructor Create(AThreadCount:integer); Destructor Destroy;override; Property ThreadNomber:integer read FThreadNomber; end; TFirstDepthThread=class(TThread) Protected FSecondDepthThreads:array[0..MaxThread] of TSecondDepthThread; Procedure Execute;override; Public SendingDataQuery:TThreadedQueue<TBytes>; constructor Create; Destructor Destroy;override; end; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FFirstDepthThread:TFirstDepthThread; { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses SyncObjs,TypInfo; {$R *.dfm} Constructor TSecondDepthThread.Create(AThreadCount: Integer); begin FError:=false; TickInterval:=2000+random(3000); FThreadNomber:=AThreadCount; SendingDataQuery:=TThreadedQueue<TBytes>.Create(100, 1, 1); //инициализация очереди FreeOnTerminate := false; Inherited Create(false); end; Destructor TSecondDepthThread.Destroy; begin FreeAndNil(SendingDataQuery); inherited; end; Procedure TSecondDepthThread.Execute; var iCounterPerSec,TimeStart, TimeFinish: TLargeInteger; QSize:integer; WaitResult:TWaitResult; ReceivedData:TBytes; ElapsedTime:double; begin NameThreadForDebugging('SecondDepthThread_'+inttostr(FThreadNomber)); while (not Terminated)do begin QueryPerformanceFrequency(iCounterPerSec); QueryPerformanceCounter(TimeStart); WaitResult:=SendingDataQuery.PopItem(QSize,ReceivedData); QueryPerformanceCounter(TimeFinish); ElapsedTime:= (TimeFinish - TimeStart)/iCounterPerSec; if (ElapsedTime<0.000082)and(WaitResult=TWaitResult.wrTimeout)and(not FError) then begin {жучок 1} OutputDebugString(pchar('Поток№ '+inttostr(FThreadNomber)+ ' Всё.., началось! Ответ(состояние) очереди='+ GetEnumName(TypeInfo(TWaitResult), Ord(WaitResult))+' выполнение за '+ FormatFloat('0.000000', ElapsedTime) + ' сек., а должно быть более 0.001 сек')); FError:=true; // дальше сообщения с wrTimeout не выводим, т.к. их слишком много end; if (WaitResult=TWaitResult.wrSignaled)and(length(ReceivedData)>0) then begin if ReceivedData[0]=100+FThreadNomber then {OutputDebugString(pchar('Поток№ '+inttostr(FThreadNomber)+ ' ,есть корректные данные'))}; if ReceivedData[0]<>100+FThreadNomber then {жучок 2} OutputDebugString(pchar('Поток№ '+inttostr(FThreadNomber)+ 'некорректные данные, должно прийти'+ inttostr(100+FThreadNomber)+' ,а пришло '+inttostr(ReceivedData[0]))); if ReceivedData[0]=0 then {подвид 2-го жука} OutputDebugString(pchar('Поток№ '+inttostr(FThreadNomber)+ ' Такого быть не должно! Ответ(состояние) очереди='+ GetEnumName(TypeInfo(TWaitResult), Ord(WaitResult))+ ' сигнал о наличии данных есть, а данных нет,'+ ' выполнение за '+FormatFloat('0.000000', ElapsedTime) )); ReceivedData[0]:=0; // для контроля извлекаемых из очереди данных. end end; end; Constructor TFirstDepthThread.Create; Var Count:integer; begin for count := 0 to MaxThread do FSecondDepthThreads[Count]:=TSecondDepthThread.Create(Count); FreeOnTerminate := false; Inherited Create(false); end; Destructor TFirstDepthThread.Destroy; Var Count:integer; begin for Count := 0 to MaxThread do begin FSecondDepthThreads[Count].Terminate; FSecondDepthThreads[Count].WaitFor; FSecondDepthThreads[Count].Free; end; inherited; end; Procedure TFirstDepthThread.Execute; var Count:integer; SendingData:Tbytes; begin NameThreadForDebugging('FirstDepthThread'); Setlength(SendingData,1); while not terminated do begin for Count := 0 to MaxThread do with FSecondDepthThreads[Count] do if GetTickCount-TickSending>TickInterval then begin SendingData[0]:=100+ThreadNomber; SendingDataQuery.PushItem(SendingData); TickSending:=GetTickCount; end; sleep(1); //yield; end; end; procedure TForm1.FormCreate(Sender: TObject); begin FFirstDepthThread:=TFirstDepthThread.Create; end; procedure TForm1.FormDestroy(Sender: TObject); begin FFirstDepthThread.Terminate; FFirstDepthThread.WaitFor; FFirstDepthThread.Free; end; end.  
×
×
  • Создать...