mafulechka
mafulechka30 вересня 2019 р. 06:43

Хмарні провайдери та телеметрія через Qt MQTT

MQTT є важливим стандартом телеметрії, особливо в сценарії IoT.


Qt Company часто звертаються клієнти та користувачі Qt, щоб дізнатися, як підключитися до різних хмарних провайдерів і, бажано, щоб список вимог був коротким.

У цій статті хотілося б надати більше інформації про те, як створити з'єднання просто використовуючи Qt, без будь-яких сторонніх залежностей. Для цього порівняння вибрано такі хмарні провайдери:

• Amazon IoT Core
• Microsoft Azure IoT Hub
• Google Cloud IoT Core
• Хмарна платформа IoT Alibaba

Остаточне зведення можна переглянути в таблиці нижче.

Предмова

Перш ніж заглиблюватися в деталі, хотілося б акцентувати вашу увагу.

По-перше, основна увага приділяється підключенню пристроїв до хмари. Можливість надсилати та отримувати повідомлення є основною метою. У цій статті не буде розказано про послуги, функції або витрати самих хмарних провайдерів, коли повідомлення знаходяться у хмарі.

Крім того, ідея полягає в тому, щоб використовувати тільки Qt та/або Qt MQTT для встановлення з'єднання. Більшість, якщо не всі, постачальники надають SDK або для пристроїв, або для програм моніторингу (веб і нативних). Однак використання цих SDK розширює кількість додаткових залежностей, що призводить до підвищення вимог до сховища та пам'яті.

Порядок, в якому провайдери оцінюються в цій статті, ґрунтується на публічному використанні.

На зв'язку

Перші кроки для надсилання повідомлень - створити рішення для кожного постачальника, а потім встановити з'єднання TCP.

Amazon IoT Core

Припустимо, що ви створили обліковий запис AWS та службу IoT Core з консолі AWS у браузері.

Панель управління цього сервісу виглядає так:

Кнопка створення відкриває майстер, який допоможе налаштувати перший пристрій.

Єдина необхідна інформація – це назва пристрою. Решта елементів можна залишити порожніми.

Сервіс дозволяє автоматично створювати сертифікат для подальшого підключення.

Зберігайте сертифікати (включаючи кореневий CA) та залишайте їх доступними для використання у програмі.

Наразі жодної політики не потрібно. Цим займемося на більш пізньому етапі.

Останнім відсутнім елементом, який має розпочати реалізацію прикладу, є ім'я хоста, до якого потрібно підключитися. Зверніть увагу, що для MQTT необхідно використовувати префікс для конкретного облікового запису. Крім того, ви можете знайти інформацію на сторінці налаштувань інформаційної панелі AWS IOT.

За допомогою Qt MQTT встановлюється з'єднання з цими кількома рядками:

const QString host = QStringLiteral("<your-endpoint>.amazonaws.com");

const QString rootCA = QStringLiteral("root-CA.crt");

const QString local = QStringLiteral("<device>.cert.pem");

const QString key = QStringLiteral("<device>.private.key");

QMqttClient client;

client.setKeepAlive(10000);

client.setHostname(host);

client.setPort(8883);

client.setClientId("basicPubSub");

QSslConfiguration conf;

conf.setCaCertificates(QSslCertificate::fromPath(rootCA));

conf.setLocalCertificateChain(QSslCertificate::fromPath(local));

QSslKey sslkey(readKey(key), QSsl::Rsa);
conf.setPrivateKey(sslkey);

client.connectToHostEncrypted(conf);

Декілька деталей важливі для успішного з'єднання:

• Значення keepalive має бути в межах певного порога. 10 секунд здаються гарним показником.
• Порт 8883 є стандартним портом для зашифрованих MQTT-з'єднань.
• ClientID має бути basicPubSub . Це дійсний ідентифікатор (ID), що автоматично згенерований під час створення екземпляра IoT Core.

Microsoft Azure IoT Hub

Спочатку потрібно створити обліковий запис для порталу Azure. На панелі інструментів необхідно створити новий ресурс Iot Hub.

Спочатку панель управління може здатися приголомшливою та непереборною, оскільки Microsoft висуває на передній план безліч хмарних сервісів та функцій. Оскільки основна увага приділяється підключенню першого пристрою, найпростіший спосіб - перейти до Shared access policies (Політика загального доступу) і створити нову політику доступу з усіма включеними правами.

Це вкрай небажано у виробничому середовищі з міркувань безпеки.

Вибравши щойно створену політику, можна скопіювати рядок підключення.

Далі буде використовуватись програма Azure Device Explorer. Ця програма ідеально підходить для тестування. Після запуску введіть Сonnection string (Рядок підключення) зверху в редагування тесту підключення та натисніть Update (Оновити) .

Вкладка керування дозволяє створювати нові тестові пристрої із зазначенням автентифікації через X509 або Security Keys (Ключі безпеки). Security Keys - це заздалегідь обраний стандартний метод, якого прагнемо.

Нарешті, Device Explorer дозволяє створити SAS token, який буде потрібно для налаштування клієнта MQTT. Token має таку форму:

HostName=<yourIoTHub>.azure-devices.net;DeviceId=<yourDeviceName>;SharedAccessSignature=SharedAccessSignature sr==<yourIoTHub>.azure-devices.net%2F…..

Потрібна лише ця частина для аутентифікації:

SharedAccessSignature sr==<yourIoTHub>.azure-devices.net%2F…..

Azure IoT Hub також використовує TLS для підключення. Щоб отримати root CA (кореневий центр сертифікації), можна клонувати Azure IoT C SDK або отримати DigiCert Baltimore Root Certificate вручну. Ні веб-інтерфейс, ні Device Explorer (браузер пристроїв) не надають його.

Щоб встановити з'єднання з Qt за допомогою Qt MQTT, код виглядає так:

const QString iotHubName = QStringLiteral("<yourIoTHub>");
const QString iotHubHostName = iotHubName + QStringLiteral(".azure-devices.net");
const QString deviceId = QStringLiteral("<yourDeviceName>");

QMqttClient client;
client.setPort(8883);
client.setHostname(iotHubHostName);
client.setClientId(deviceId);
client.setUsername(iotHubHostName + QStringLiteral("/") + deviceId + QStringLiteral("/?api-version=2018-06-30"));
client.setPassword(QLatin1String("SharedAccessSignature sr=<yourIoTHub>.azure-devices.net%2Fdevices…"));

auto caCerts = QSslCertificate::fromData(QByteArray(certificates));
QSslConfiguration sslConf;
sslConf.setCaCertificates(caCerts);

client.connectToHostEncryped(sslConf);

Ядро Google Cloud IoT

Після того, як ви створили обліковий запис для Google Cloud Platform, веб-інтерфейс надає майстер для запуску першого проекту з використанням Cloud IoT Core.

Після того, як проект був створений, може виникнути трудноща зі знаходженням вашого реєстру. У реєстрі зберігається вся інформація про пристрої, зв'язок, правила і т.д.

Як і Microsoft Azure, всі доступні служби розміщені на панелі інструментів. Ви знайдете елемент IoT Core у розділі Big Data (Важливі дані) з лівого боку.

Після використання Google Cloud Platform, пошук виявиться дуже корисним для переходу на цільову сторінку.

Із самого реєстру тепер можна додавати нові пристрої.

Інтерфейс запитує ключі/сертифікати для вашого пристрою. Але в нього немає можливості створити щось із самого сервісу. Існує документація про те, як їх створити. І на стадії виробництва ці етапи, ймовірно, будуть автоматизовані в інший спосіб. Однак для початку роботи необхідні додаткові кроки, які можуть спричинити скруту.

Як тільки ваш пристрій внесено до Реєстру, ви можете почати з реалізації на стороні клієнта.

На відміну від інших провайдерів, Google Cloud IoT Core не використовує сертифікат пристрою під час створення з'єднання. Натомість закритий ключ використовується для створення пароля. Сам пароль має бути згенерований, як JSON Web Token. Хоча JSON Web Token є відкритим галузевим стандартом, це додає ще одну залежність до вашого проекту. Щось має бути в змозі створити ці Token'и. Google надає приклад коду, але потрібна адаптація для включення його до програми.

Ідентифікатор (ID) клієнта для з'єднання MQTT складається з кількох параметрів і має таку форму:

projects/PROJECT_ID/locations/REGION/registries/REGISTRY_ID/devices/DEVICE_ID

З особистого досвіду, слід враховувати чутливість до регістру. Все, крім ідентифікатора проекту (Project ID), зберігає ту ж велику літеру, що і ваш проект, реєстр і пристрій. Тим не менш, ідентифікатор проекту зберігатиметься у нижньому регістрі.

Враховуючи все це, найпростіша реалізація для встановлення з'єднання виглядає так:

const QString rootCAPath = QStringLiteral("root_ca.pem");
const QString deviceKeyPath = QStringLiteral("rsa_private.pem");
const QString clientId = QStringLiteral("projects/PROJECT_ID/locations/REGION/registries/REGISTRY_ID/devices/DEVICE_ID");
const QString googleiotHostName = QStringLiteral("mqtt.googleapis.com");
const QString password = QByteArray(CreateJwt(deviceKeyPath, "<yourprojectID>", "RS256"););

QMqttClient client;
client.setKeepAlive(60);
client.setPort(8883);
client.setHostname(googleiotHostName);
client.setClientId(clientId);
client.setPassword(password);

QSslConfiguration sslConf;
sslConf.setCaCertificates(QSslCertificate::fromPath(rootCAPath));

client.connectToHostEncrypted(sslConf);

Хмарна платформа Інтернету речей Alibaba

Alibaba Cloud IoT Platform є єдиним продуктом, що має кілька варіантів: базову та професійну версії. На момент написання цієї статті структура цього продукту, схоже, зазнала змін. Але це не впливає на досліджувані питання, пов'язані з MQTT.

Після створення облікового запису Alibaba Cloud веб-панель дозволяє створити новий екземпляр IoT Platform.

Після створення екземпляра інтерфейс майстра дозволяє створювати продукт та пристрій.

З них знадобиться кілька деталей для встановлення MQTT-з'єднання.

• Ключ продукту
• Секрет продукту
• Device Name (Ім'я пристрою)
• Device Secret (Секрет пристрою)

Реалізація потребує додаткових кроків. Щоб отримати всі специфічні властивості MQTT, ідентифікатор клієнта, ім'я користувача та пароль створюються шляхом об'єднання та підписування.

Для підключення екземпляра клієнта QMqtt цього достатньо.

iotx_dev_meta_info_t deviceInfo;
qstrcpy(deviceInfo.product_key, "<yourproductkey>");
qstrcpy(deviceInfo.product_secret, "<yourproductsecret>");
qstrcpy(deviceInfo.device_name, "<yourdeviceID>");
qstrcpy(deviceInfo.device_secret, "<yourdeviceSecret>");

iotx_sign_mqtt_t signInfo;
int32_t result = IOT_Sign_MQTT(IOTX_CLOUD_REGION_GERMANY, &deviceInfo, &signInfo);

QMqttClient client;
client.setKeepAlive(10000);
client.setHostname(QString::fromLocal8Bit(signInfo.hostname));
client.setPort(signInfo.port);
client.setClientId(QString::fromLocal8Bit(signInfo.clientid));
client.setUsername(QString::fromLocal8Bit(signInfo.username));
client.setPassword(QString::fromLocal8Bit(signInfo.password));

client.connectToHost();

Qt Company не використовує QMqttClient::connectToHostEncrypted() , як усі інші провайдери. Alibaba Cloud IoT Platform є єдиним постачальником, який за умовчанням використовує не TLS-з'єднання. Документовано, що можна використовувати один, а також отримати rootCA. Однак той факт, що це можливо, таки дивує.

Стандартний висновок (обмеження)

До цього часу ми встановлювали MQTT-з'єднання з кожним із постачальників IoT. Кожен постачальник використовує трохи відмінний від інших підхід для ідентифікації та аутентифікації пристрою, але всі ці сервіси відповідають стандарту MQTT 3.1.1.

Однак, для подальших кроків розробники повинні знати про певні обмеження або варіації стандарту. Це обговорюватиметься далі.

Жоден з провайдерів немає вбудованої підтримки quality-of-service (QoS) level 2. Деякою мірою це має сенс, оскільки телеметричної інформації не потрібно багаторазових кроків для перевірки доставки повідомлення. Чи буде повідомлення оброблено та перевірено, не становить особливого інтересу в даному випадку, хоча розробник повинен знати про це обмеження.

Щоб освіжити пам'ять термінології, давайте коротко резюмуємо, що таке збережені повідомленням і «повідомленням волі».

Збережені повідомлення зберігаються на сервері для майбутніх передплатників, щоб отримувати останню інформацію з доступних тем. «Повідомлення волі» вбудовані у запит на підключення та будуть поширюватися лише у разі несподіваного відключення від клієнта.

Amazon IoT Core

Ідентифікатор клієнта використовується для визначення пристрою. Якщо другий пристрій використовує той самий ідентифікатор під час спроби підключення, перший пристрій буде вимкнено без будь-якого повідомлення. Другий пристрій успішно підключиться, якщо код програми містить своєрідне автоматичне перепідключення, це може призвести до недоступності всіх пристроїв з однаковим ідентифікатором клієнта.

Збережені повідомлення не підтримуються AWS, і спроба надіслати надіслане повідомлення призведе до закриття з'єднання.

AWS IoT Core підтримує "повідомлення волі" в рамках дозволених тем.

Microsoft Azure IoT Hub

Ідентифікатор клієнта використовується для визначення пристрою. Поведінка двох пристроїв з однаковим ідентифікатором така сама, як і для Amazon IoT Core.

Збережені повідомлення не підтримуються в IoT Hub. Однак у документації говориться, що Hub внутрішньо додасть прапорець, щоб сервер знав, що повідомлення були задані як збережені.

«Повідомлення волі» дозволено та підтримуватись, враховуючи обмеження теми, які будуть обговорюватися нижче.

Ядро Google Cloud IoT

Цей провайдер використовує ідентифікатор клієнта та пароль для успішної ідентифікації пристрою.

Повідомлення, позначені як збережені, втрачають цю опцію під час доставки. Згідно з журналами налагодження, вони передаються як звичайні повідомлення. Не знайдено жодної документації про те, чи він може працювати аналогічно Azure IoT Hub, який перенаправляє цей запит у внутрішню чергу повідомлень.

"Повідомлення волі", здається, не підтримуються. Незважаючи на те, що можна зберегти повідомлення волі в операторі підключення, воно ігнорується у разі нерегулярного відключення.

Хмарна платформа Інтернету речей Alibaba

Трійка ідентифікатора клієнта, імені користувача та пароля використовується для ідентифікації пристрою у продукті.

І прапор зберігання, і повідомлення волі ігноруються з боку сервера. Повідомлення із зазначеним збереженням пересилається, як звичайне повідомлення і втрачається після доставки. Повідомлення волі» ігноруються і ніде не зберігаються під час з'єднання.

Доступні (користувацькі) теми

MQTT використовує ієрархію тем для створення детального контексту для повідомлень. Теми схожі на структуру каталогів, починаючи від загального до конкретного пристрою. Одним із прикладів ієрархії тим буде
Sensors (Датчики)/Europe (Європа)/Germany (Німеччина)/Berlin (Берлін)/device_xyz/temperature (температура).

Кожен провайдер IoT обробляє теми по-своєму, тому розробники мають бути дуже обережними з цим розділом.

Amazon IoT Core

По-перше, необхідно перевірити, які теми можна використовувати за промовчанням. На панелі інструментів перейдіть до розділу Secure (Безпека)-> Policies (Політики) та виберіть створену за промовчанням policy. Це має виглядати так:

AWS IoT Core визначає політики у форматі JSON, і ви знайдете деякі з попередніх деталей, зазначених у цьому документі. Наприклад, доступні ідентифікатори клієнта вказуються у ресурсі Connect. Це також дозволяє оголосити, які теми є дійсними для публікації, підписки та отримання. Можна мати кілька політик, і вони мають бути прив'язані до пристроїв. Таким чином, він допускає деталізовану модель безпеки, за якої певні типи груп мають різні права доступу.

Зверніть увагу, що опис теми також дозволяє використовувати підстановочні знаки. Їх не слід плутати з підстановними знаками у стандарті MQTT. Це означає, що ви повинні використовувати "*" замість "#", щоб увімкнути всі підтеми.

Після того, як ви створили ієрархію тим, що базується на ваших потребах, сам код простий і виглядає так:

client.publish(QStringLiteral("topic_1"), "{\"message\":\"Somecontent\"}", 1);
client.subscribe(QStringLiteral("topic_1"), 1);

Microsoft Azure IoT Hub

IoT Hub просто виступає як інтерфейс для підключення існуючих рішень MQTT до Hub. Користувачеві не дозволяється вказувати будь-яку тему користувача, а також не можна вводити ієрархію тем.

Повідомлення може бути опубліковане лише у такій формі:

const QString topic = QStringLiteral("devices/") + deviceId + QStringLiteral("/messages/events/");
client.publish(topic, "{id=123}", 1);

Для передплат існують аналогічні обмеження.

client.subscribe(QStringLiteral("devices/") + deviceId + QStringLiteral("/messages/devicebound/#"), 1);

Підстановка підписки використовується для отримання додаткової інформації, яку IoT Hub може додати до повідомлення. Наприклад, це може бути ідентифікатор повідомлення. Для об'єднання кількох властивостей, сама підтема кодується, як URL. Приклад повідомлення, надісланого з IoT Hub, містить тему:

devices/TestDevice01/messages/devicebound/%24.mid=7493c5cc-d783-4ecd-8129-d3c87590b544&%24.to=%2Fdevices%2FTestDevice01%2Fmessages%2FdeviceBound&iothub-ack=full

Ядро Google Cloud IoT

За замовчуванням клієнт MQTT повинен використовувати цю тему для публікації:

/devices/<deviceID>/events

Але також можна додати додаткові теми за допомогою Google Cloud Shell або інших API.

У цьому випадку було створено тему customCross . Додаткові теми відображені, як підтеми на стороні MQTT, якщо опублікувати повідомлення на цю тему, це виглядатиме так:

/devices/<deviceID>/events/customCross

Для підписок теми недоступні, і є тільки дві доступні теми, на які клієнт може підписатися:

/devices/<deviceID>/commands/#
/devices/<deviceID>/config/

Конфіг-повідомлення - це збережені повідомлення з хмари. Вони будуть надсилатись при кожному підключенні клієнта для синхронізації пристрою.

Хмарна платформа Інтернету речей Alibaba

Теми можна легко керувати у вкладці «Topic Categories» (Категорії тем) на панелі інструментів продукту.

Кожна тема може бути налаштована для отримання, надсилання або двонаправленого зв'язку. Крім того, пара додаткових тем генерується за умовчанням, щоб допомогти створити структуру, що масштабується.

Зауважте, що тема завжди містить ідентифікатор пристрою. Це має значення для маршрутів зв'язку, як зазначено нижче.

Маршрути зв'язку

Спілкування в контексті IoT можна розділити на три категорії:

  1. З пристрою в хмару (D2C)
  2. Cloud to Device (C2D)
  3. Від пристрою до пристрою (D2D)

Перша категорія є найпоширенішою. Пристрої надають інформацію про стан, дані датчика або будь-яку іншу інформацію. Розмова в іншому напрямку відбувається у разі надання інструкцій поведінки, керування рівнями налагодження чи будь-яких загальних інструкцій.

Що стосується зв'язку між пристроями, то потрібно бути багатослівним у визначенні в цьому контексті. Типовий приклад можна взяти із домашньої автоматизації. За певної інтенсивності світла датчик поширює інформацію, і жалюзі реагують на це автоматично, опускаючись. Тут усі алгоритми обробляються на пристроях та хмарний інтелект не потрібний. Крім того, не потрібно створювати додаткові правила або фільтри у самому хмарному екземплярі. Також всі протестовані провайдери можуть створити екземпляр методу, що працює у хмарі, а потім перенаправити команду на інший пристрій.

У попередньому розділі ми вже розглянули випадки D2C та C2D. Після визначення ієрархії тим клієнт може опублікувати ці теми, і навіть підписатися ними.

Щоб переконатися, що з'єднання C2D працює, виберіть вкладку «Test» (Тест) у лівій частині панелі інструментів. Браузер покаже мінімальний інтерфейс, який дозволяє надсилати повідомлення із зазначеною темою.

Крім того, випадок device-to-device (від пристрою до пристрою) добре обробляється шляхом підписки та публікації у темі, як зазначено у політиці.

Microsoft Azure IoT Hub

Можна надсилати повідомлення з пристрою у хмару та навпаки. Тим не менш, користувач не може вільно вибирати тему.

Для відправки Device Explorer – гарна утиліта, особливо для тестування якості пакета властивостей.

Зв'язок між пристроями неможливий при використанні Azure IoT Hub.

Ядро Google Cloud IoT

Можливе надсилання повідомлень із пристрою в хмару, що забезпечує додаткову деталізацію з підтемами для публікації. Повідомлення приймаються на дві доступні теми, як описано в розділі вище.

Оскільки розділи користувача як і раніше містять ідентифікатор пристрою, неможливо використовувати екземпляр Google Cloud IoT Core як стандартний посередник для розповсюдження повідомлень між пристроями (D2D).

Панель інструментів для пристрою дозволяє надсилати команду, а також конфігурацію з хмарного інтерфейсу на пристрій.

Хмарна платформа Інтернету речей Alibaba

Публікація та Передплата можуть здійснюватися гнучким чином із використанням платформи IoT. (Під)Теми можуть бути згенеровані, щоб забезпечити більше структури.

Щоб перевірити надсилання повідомлення з хмари на пристрій, Topic List (Список тем) на панелі інструментів пристрою містить діалогове вікно.

Зв'язок між пристроями також можливий. Теми для них не можуть бути вільно визначені, вони повинні бути рівно на один рівень нижче.

/broadcast/<yourProductName>/

Тема на цьому рівні може бути обрана вільно.

Рекомендації та інше

Amazon IoT Core

• Особливості MQTT для AWS.
• Доступні стандартні теми.
• Посібник із проектування для ієрархій тем, також дуже хороший довідник для проектів, не пов'язаних з AWS.

Microsoft Azure IoT Hub

• Особливості MQTT для Azure.

Ядро Google Cloud IoT

• Особливості MQTT для Cloud IoT Core.
• Генерація ключів для пристроїв.
• Команди.

Хмарна платформа Інтернету речей Alibaba

• Особливості MQTT для хмарної платформи IoT.
• Посібник із підключення.

Додаткові примітки

Версія 5 MQTT (MQTT version 5) , здається, занадто молодою, щоб її могли прийняти найбільші постачальники. Це дуже сумно з огляду на те, що останній стандарт додає пару функцій, особливо корисних у світі IoT. Спільно використовувані підписки забезпечують автоматичне балансування завдань, нова команда аутентифікації забезпечує більшу гнучкість реєстрації пристроїв, властивостей підключення та повідомлень, що робить хмарні підключення більш продуктивними, їх простіше обмежувати/налаштовувати тощо. Але на даний момент доведеться чекати на його прийняття.

Знову ж таки, хотілося б підкреслити, що розробники не розглядали жодну з функцій, які вищезгадані рішення IoT надають для обробки повідомлень після їх отримання. Це частина зовсім іншого дослідження.

Крім того, не було розглянуто використання RPC-провайдерами. Деякі мають жорстко закодовані теми для обробки RPC, такі як Google, які розрізняють команди та конфігурацію. Alibaba навіть використовує стандартні теми для обробки повідомлень про оновлення прошивки через MQTT. TrendMicro опублікував дослідження проблем безпеки в MQTT і RPC займає там помітне місце, яке обов'язково потрібно прочитати всім, хто налаштовує архітектуру MQTT з нуля.

Як я можу перевірити це сам?

Розробники створили зразок програми, яка дозволяє підключатися до будь-якого з перелічених постачальників хмарних послуг, коли доступні необхідні відомості. Сам інтерфейс досить простий:

Заключні слова

Для будь-якого ширшого провайдера IoT та хмарних послуг можна підключити програму на основі телеметрії, використовуючи MQTT (і Qt MQTT). Кожен з них має різні варіанти деталей підключення, в тому числі стандарт, який повністю доступний для розробників.

Розробники Qt Company з нетерпінням чекають на прийняття MQTT версії 5. Команда AUTH забезпечує кращу інтеграцію методів аутентифікації, а інші функції, такі, як псевдоніми тем та властивості, вносять додаткові сценарії використання у світ IoT. Крім того, підписка, що розділяється, корисна для створення відносин між даними і пристроями. Цей останній пункт може наступити на ноги хмарним постачальникам, оскільки їхня мета – впоратися з навантаженням усередині хмари.

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 листопада 2024 р. 06:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject04 червня 2022 р. 03:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Слідкуйте за нами в соціальних мережах