Страница 1 из 1

Как правильно передать/прочитать запись по TUDPBlockSocket?

СообщениеДобавлено: 11.03.2016 12:31:54
kosteek
Сделал такой вид записи с динамическим массивом
Код: Выделить всё
type
  ons = record
    version: Byte;
    statusPacket: Byte;
    statusClient: Byte;
    lengthIdentify: Byte;
    Identefer: array[0..31] of char;
    lengthMsg: integer;
    msg:array of char;
  end;

Код: Выделить всё
UDPServer: TUDPBlockSocket;
msg: ons;

Код: Выделить всё
UDPServer.RecvBuffer(@msg,sizeof(ons));


Не могу понять как правильно прочитать его с помощью TUDPBlockSocket. Структуру считывает до динамического массива правильно, но в динамический массив попадает ерунда.

Но если вместо динамического массива использовать обычный массив, все замечательно работает.

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 11.03.2016 12:48:47
Дож
Динамический массив не хранится сам в записи, в записи хранится только указатель на то место в памяти, где реально размещён динамический массив. sizeof(ons) — это не функция, а константа. Сериализовать динамический массив нужно самостоятельно. Например, записав сперва длину массива, потом все его элементы.

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 11.03.2016 15:03:38
kosteek
Спасибо Дож. Тоже самое будет если вместо динамического массива укажу тип String.
Массив сериализовал
Код: Выделить всё
  SetLength(msg.msg, length(s));
  for i:=0 to length(s)-1 do msg.msg[i]:=s[i+1];

Подскажи как правильно отправить?

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 11.03.2016 15:11:26
Дож
Что будет со String зависит от того, является ли он алиасом на AnsiString (в этом случае действительно как дин. массив ведёт себя) или ShortSring (в этом случае хранит строку по месту).

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 11.03.2016 16:12:09
wavebvg
kosteek, string будет указывать на адрес первого байта PChar-а.
Данные не имеющие фиксированного (максимального) размера не получится прочитать за одну операцию (вначале читаем размер, потом данные).
Если есть какие-либо ограничения сверху на размер ons - то лучше использовать массив фиксированной длины.
Если ограничения нет - тогда можно в отправляемый буфер с ons в конец дописать данные из msg. При чтении, вначале, читаем ons, а потом, зная размер, читаем оставшиеся данные в заранее подготовленный буфер и назначаем его [буфер] msg-у.

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 11.03.2016 16:26:10
kosteek
wavebvg, а как отправить в одном udp пакете ons и msg?

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 11.03.2016 17:02:48
Дож
kosteek писал(а):wavebvg, а как отправить в одном udp пакете ons и msg?

Нужно в этом сообщении сперва записать ons (без массива), потом длину массива, потом элементы массива.

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 12.03.2016 12:37:48
wavebvg
Посмотрел, как сейчас в синапсе.

Проще всего так (идея - засунуть даные в строку и не маяться с её управлением, сам не проверял):
Код: Выделить всё
var
  Msg, Resp: ons;
  Send, Recv: TStringStream;

Записываем данные:
Код: Выделить всё
Send.Write(Msg, SizeOf(Msg) - SizeOf(Msg.msg));
Send.Write(Msg.msg[1], Length(Msg.msg));

Отправляем данные:
Код: Выделить всё
UDPServer.SendString(Send.DataString);

Читаем данные ответа:
Код: Выделить всё
Recv.DataString := Socket.RecvString(5000);

Заполняем структуру:
Код: Выделить всё
Recv.Position := 0;
Recv.Read(Resp, SizeOf(Resp) - SizeOf(Resp.msg));
SetLength(Resp.msg, Resp.lengthMsg);
Recv.Read(Resp.msg[1], Resp.lengthMsg);

Re: Как правильно передать/прочитать запись по TUDPBlockSock

СообщениеДобавлено: 12.03.2016 15:21:19
kosteek
wavebvg, благодарю, получилось отправлять и получать.
изменил запись, вместо динамического массива использую String
Код: Выделить всё
type
  ons = record
    version: Byte;
    statusPacket: Byte;
    statusClient: Byte;
    lengthIdentify: Byte;
    Identefer: array[0..31] of char;
    lengthMsg: integer;
    msg:string;
  end;

Твой пример с запись отлично сработал, а вот с чтением повозился.
Рабочий код чтения
Код: Выделить всё
procedure TUDPServer.Execute;
var
  msg : ons;
  Recv:TStringStream;
  s:string;
begin

  while (not Terminated) do
    begin
        s:='';
        msg.msg:='';
        Recv:=TStringStream.Create(s);
        recv.WriteString(UDPServer.RecvPacket (100));
        Recv.Position:=0;
        if Recv.Size > 0 then
          begin
               Recv.Read(msg,sizeof(msg)-sizeof(msg.msg));
               if msg.lengthMsg > 0 then
                 begin
                      msg.lengthMsg:=LEtoN(msg.lengthMsg);
                      SetLength(msg.msg,msg.lengthMsg);
                      msg.msg:=Recv.ReadString(msg.lengthMsg);

                 end;
               fStatusText := msg;
               Synchronize(@Showstatus);

          end;
        FreeAndNil(Recv);
    end;
end;


Еще раз поблагодарю всех кто участвовал в обсуждении.