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

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Ответить
kosteek
постоялец
Сообщения: 203
Зарегистрирован: 24.07.2008 14:57:09
Откуда: Украина, г.Славянск

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

Сообщение 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. Структуру считывает до динамического массива правильно, но в динамический массив попадает ерунда.

Но если вместо динамического массива использовать обычный массив, все замечательно работает.
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

Динамический массив не хранится сам в записи, в записи хранится только указатель на то место в памяти, где реально размещён динамический массив. sizeof(ons) — это не функция, а константа. Сериализовать динамический массив нужно самостоятельно. Например, записав сперва длину массива, потом все его элементы.
kosteek
постоялец
Сообщения: 203
Зарегистрирован: 24.07.2008 14:57:09
Откуда: Украина, г.Славянск

Сообщение kosteek »

Спасибо Дож. Тоже самое будет если вместо динамического массива укажу тип String.
Массив сериализовал

Код: Выделить всё

  SetLength(msg.msg, length(s));
  for i:=0 to length(s)-1 do msg.msg[i]:=s[i+1];

Подскажи как правильно отправить?
Последний раз редактировалось kosteek 11.03.2016 14:13:36, всего редактировалось 1 раз.
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

Что будет со String зависит от того, является ли он алиасом на AnsiString (в этом случае действительно как дин. массив ведёт себя) или ShortSring (в этом случае хранит строку по месту).
wavebvg
постоялец
Сообщения: 355
Зарегистрирован: 28.02.2008 03:57:35

Сообщение wavebvg »

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

Сообщение kosteek »

wavebvg, а как отправить в одном udp пакете ons и msg?
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

kosteek писал(а):wavebvg, а как отправить в одном udp пакете ons и msg?

Нужно в этом сообщении сперва записать ons (без массива), потом длину массива, потом элементы массива.
wavebvg
постоялец
Сообщения: 355
Зарегистрирован: 28.02.2008 03:57:35

Сообщение 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);
kosteek
постоялец
Сообщения: 203
Зарегистрирован: 24.07.2008 14:57:09
Откуда: Украина, г.Славянск

Сообщение 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;


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