Отправка байтового массива (тип `ay`) по D-Bus с использованием GDBus
Я пытаюсь массив байтов по D-Bus, используя привязки GDBus. Пожалуйста, дайте мне знать, как я могу этого достичь. Я пытался гуглить, но не помогло.
Байт массив содержит файл изображения, поэтому не может быть преобразован в charbytearray
Любая помощь оценивается
4 ответа
У этого вопроса есть несколько хороших идей в ответах, включая передачу больших объемов данных путем записи данных в файл и передачи имени файла или использования именованного канала. Запись в файл и передача имени файла может быть проще всего реализовать.
Я сделал несколько тестов, используя XML, где я использовал тип ay
, Это хорошо работает с привязкой QT (генерируется с qdbusxml2cpp
) где это переводится на QByteArray
однако кажется, что он не работает с привязкой glib (генерируется с gdbus-codegen
) где это переводится в gchar *
и кажется, что ты теряешь то, что после \0
- потому что так или иначе это обрабатывается как строка. Однако вы найдете, что:
Это автоматическое сопоставление можно отключить с помощью аннотации org.gtk.GDBus.C.ForceGVariant - если используется, то
GVariant
всегда заменяется вместо соответствующего собственного типа C. Эту аннотацию может быть удобно использовать при использовании строк байтов (строка типаay
) для данных, которые могут иметь встроенные байты NUL.
Что означает в соответствии с https://developer.gnome.org/gio/stable/gdbus-codegen.html что вы можете справиться с этим как GVariant
, Я проверил это, добавив тег для аннотации org.gtk.GDBus.C.ForceGVariant
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
на каждом арге и все работает.
На самом деле, вместо использования типа "ay", вы можете использовать "a(y)". Привязка glib переводит "a (y)" в GVariant*.
И тогда вы можете использовать обработку "GVariant" для работы с параметром.
например, XML-файл
<method name="parsePacket">
<arg direction="in" name="message" type="a(y)">
<doc>
<line>type: const Uint8 *</line>
</doc>
</arg>
</method>
Сгенерированный метод:
gboolean (*handle_parse_packet) (
IDbusObject *object, GDBusMethodInvocation *invocation, GVariant *arg_message);
gboolean idbusobject_call_parse_packet_sync (
IDbusObject *proxy,
GVariant *arg_message,
GCancellable *cancellable,
GError **error);
Вы можете извлекать и вставлять данные, используя метод "GVariant".
Вставьте данные на стороне клиента:
void parsePacket (unsigned char* arg_message, guint16 arg_length)
{
GVariantBuilder *builder;
GVariant *value;
builder = g_variant_builder_new (G_VARIANT_TYPE ("a(y)"));
for (int i = 0; i < arg_length; i++)
{
g_variant_builder_add (builder, "(y)", arg_message[i]);
}
value = g_variant_new ("a(y)", builder);
g_variant_builder_unref (builder);
idbusobject_call_parse_packet_sync(proxy,
value,
NULL,
NULL);
}
Извлечь данные на стороне сервера:
gboolean handleParsePacket (
IDbusObject *object,
GDBusMethodInvocation *invocation,
GVariant *arg_message)
{
unsigned char byteArray[2048];
int actualLength = 0;
GVariantIter *iter;
guchar str;
g_variant_get (arg_message, "a(y)", &iter);
while (g_variant_iter_loop (iter, "(y)", &str))
{
byteArray[actualLength++] = str;
}
g_variant_iter_free (iter);
idbusobject_complete_parse_packet( object, invocation);
return (TRUE);
}
На стороне клиента вы могли бы сделать это проще, вызвав метод g_variant_new_from_data():
GVariant* convertByteArrayToVariant(unsigned char* arg_message, guint16 arg_length)
{
return g_variant_new_from_data(
G_VARIANT_TYPE ("a(y)"),
arg_message,
arg_length,
TRUE,
NULL,
NULL);
}
Или, если у вас есть заполненный GByteArray*, вы можете сделать это следующим образом:
GVariant* convertByteArrayToVariant(GByteArray* array)
{
return g_variant_new_from_data(
G_VARIANT_TYPE ("a(y)"),
array->data,
array->len,
TRUE,
NULL,
NULL);
}