суббота, 15 ноября 2014 г.

20. ZeroMQ и Delphi: CZMQ, varargs и типы аргументов (zsock_bind(), zsock_connect(), zsock_send(), zsock_recv() и т.д.)


Использование функций с переменным числом аргументов.



В CZMQ появилось много методов с переменным число аргументов. В описании таких методов присутствует модификатор varargs: например:


function zsock_connect(p_self: p_zsock_t; format: PChar): Integer; varargs; 
  cdecl; external cZMQ_DllName;

или

function zsock_send(self: Pointer; picture: PChar): Integer; varargs; 
  cdecl; external cZMQ_DllName;


Как ими пользоваться?



В первом случае (zsock_connect) дополнительные параметры являют аргументами Си-шного классического format-а:

zsock_connect(fSocket, 'tcp://%s:%d', pChar('localhost'), 5555);

В данном случае %s будет заменен null-terminated строкой 'localhost', %d - целым числом 5555. Если есть сомнения в типе данных - используем явное приведение типа.


zsock_connect(fSocket, 'tcp://%s:%d', pChar('localhost'), integer(5555));

Во втором случае (zsock_send) дополнительные параметры являют аргументами format-а от CZMQ, маска формата задается в аргументе picture. Picture - это строка, которая определяет тип каждого кадра сообщения и может содержать любые из следующих символов, каждый из которых соответствует нулю, одному, или двум дополнительным аргументам:

      i = integer   
      s = PChar (указатель на null - terminated строку)
      b = pByte, size_t (2 аргумента: указатель на массив байтов и длина массива)
      c = p_zchunk_t
      f = p_zframe_t
      h = p_zhash_t
      m = p_zmsg_t (будут отправлены все кадры zmsg)
      p = Pointer (отправляет значение указателя, имеет смысл только для протокола inproc)
      z = отправляет пустой кадр-разделитель (0 аргументов)

Замечание:  s, b, c и f кодируются одинаковым способом; интерпретация данных возложена на клиента.

Пример:
var
  fB : Byte;
...
begin 
  fB := 127;
  zsock_send(fSocket, 'izsb', Integer(3), PChar('Hello!'), @fB, Integer(1))

Будут отправлены кадры:
  i - целое, значение 3.
  z - пустой кадр-разделитель.
  s - строка 'Hello.
  b - один байт, значение 127.

 Метод zsock_send не меняет пересылаемые данные (кроме случая с m). Для метода zsock_recv:

...

С методом

function zsock_recv(self: Pointer; picture: PChar): Integer; varargs; 
  cdecl; external cZMQ_DllName;


 дело обстоит несколько иначе:

      i = pInteger (размещает принятое целое по указанному адресу)
      s = ^pChar (принимает/создает строку, адрес которой помещает по указанному адресу)
      b = ^pByte, ^size_t (2 аргумента) (принимает массив данных, адрес помещает по указанному адресу, длину помещает в целое по указанному адресу)
      c = ^p_zchunk_t (создает чанк, адрес помещает по указанному адресу)
      f = ^p_zframe_t (создает zframe, адрес помещает по указанному адресу)
      p = ^Pointer (размещает принятый указаетль по указанному адресу)
      h = ^p_zhash_t(создает zhash, адрес помещает по указанному адресу)
      m = ^p_zmsg_t (создает zmsg со всеми кадрами, адрес помещает по указанному адресу)
      z = пусто, "проглатывает" пустой кадр (0 аргументов)

Пример:
var
  fB : pByte;
  fCnt : Integer;
  fInt : Integer;
  fStr : PChar; 
 ...
begin 
  zsock_recv(fSocket, 'izsb', @fInt, @fStr, @fB, @fCnt)

Будут приняты кадры:
  i - целое, значение будет помещено в fInt

  z - пустой кадр-разделитель.
  s - строка, адрес будет помешен в fStr.
  b - массив байт, адрес будет помещен в fB, длина массива - в fCnt.

Таким образом, аргументами являются указатели,  по которым размещаются принятые данные. Если значение указателя - nil, соответствующий кадр будет пропущен (не размещен в памяти).
После использования созданных объектов следует освободить память с помощью zstr_free():

 zstr_free(fStr);
 zstr_free(PChar(fB));

 Во всех случаях следует внимательно читать комментарии к конкретному методу и помнить, что аргументы в языке C всегда передаются только по значению.


Замечание.

Дополнительные (те, которые "varargs") параметры методов:

zsock_send(self: Pointer; picture: PChar): Integer; varargs;  cdecl; external cZMQ_DllName;
и
zsock_recv(self: Pointer; picture: PChar): Integer; varargs;  cdecl; external cZMQ_DllName;

передаются и принимаются отдельными кадрами.
Если в picture присутствует опция "m", то будет передано (принято) все сообщение из структуру p_zmsg_t. Следует учесть, что для некоторых типов сокетов при передаче автоматически вставляются дополнительные кадры, а при приеме - удаляются. Например, в сообщение, формируемое сокетами ZMQ_DEALER, в начало сообщения добавляется дополнительный кадр (идентификация). Это следует учитывать, если принять такое сообщение сокетом ZMQ_ROUTER. В то же время такой (первый) кадр будет отброшен при приеме сообщение сокетом ZMQ_DEALER.


Комментариев нет :

Отправить комментарий