Results 1 to 7 of 7

Thread: Sending Dynamic Arrays with Indy

  1. #1

    Sending Dynamic Arrays with Indy

    Hi. I've tried implementing the sending of dynamic arrays with Indy but recieve EAccessViolation error messages when I try to read the data from the server.

    My reason for using dynamic arrays is because the server holds data on the connected players. For each player there is a data type which contains an array which contains data on other players update information which the client has not yet recieved... I feel I'm explaining this really badly so here's my code client and server code....




    Code:
    Server Code:
    
    with areas[b.MID].players[i] do
     begin
      athread.Connection.WriteSmallInt(length(updates)); {Tell Client how many records they can expect to recieve }
    
      if length(updates)>0 then
       athread.Connection.WriteBuffer(updates,sizeof(updates)); { Write records }
    
      setlength(updates,0); {Set Records =0 }
     end;
     
    
    Client Code
     
       r:=idtcpclient1.ReadSmallInt(); { How Many Records Will We Recieve }
       
       if r>0 then 
        begin
         setlength(up,r);
         if r>0 then
          idtcpclient1.ReadBuffer(up,sizeof(up));
        end;
    I'm not sure if this is possible at all so any advice on whether this is possible or not and/or what im doing wrong would be great!

    Thanks!

  2. #2

    Sending Dynamic Arrays with Indy

    you should in no way be sending it as 2 seperate packets (what if the first packet is lost, deleyed, etc).

    what is in each update record?

    the way i would do it is to create a structured packet (and send each record on its own, but anyway...).

    the first 2 bytes would be the packet id. you read this from the buffer first so you can then decide what to do with it. now in this case the second 2 or 4 bytes would be the size of the array buffer. you can then check this number against the size of the packet indy received to see if it has been altered (dont want to read passed the end of the buffer) and read the number of bytes into your buffer.

    then do whatever you want with it

  3. #3

    Sending Dynamic Arrays with Indy

    Hi. Thanks for your help. Am a complete novice at this all and am new to buffers so have been working on it ever since your post and now think im starting to get somewhere.

    Does anyone know of a good tutorial for buffers? I've been searching but am yet to find any really useful tutorials. I'm a little confused about the whole area, for example I'm not sure how I can pack data into packets, the way i've been doing it so far is shown below:

    Code:
     
    c:=_UPDATE;
     main_form.IdTCPClient1.WriteBuffer(c,sizeof(c));
     main_form.IdTCPClient1.WriteBuffer(u,sizeof(u));
    This way will it be sent as a single packet or as two packets? Also I'm unsure as how to get the size of the packet recieved by Indy, although im sure if i keep on looking I'll find this out in the documentation one day...

    Thanks for your help!

  4. #4

    Sending Dynamic Arrays with Indy

    from that snippet, i would have thought it will be sent as 2 seperate packets.

    here is a code sample from one of my old projects, written with indy (not sure what version)

    [pascal]type
    TInSimPacket =packed record // General purpose 8 byte UDP packet
    Id: Array[0..3] of Char; // 3 character identifier followed by zero character
    Value: Integer; // 32 bit value depending on the type of InSimPack
    end;


    TRST_Packet =packed record // Race Start
    RST: Array[0..3] of Char;
    RaceLaps: Byte; // 0 if qualifying
    QualMins: Byte; // 0 if race
    NumInRace: Byte;
    Spare: Byte;

    Track: Array[0..5] of Char;
    Weather: Byte;
    Wind: Byte;

    Sp0: Byte;
    Sp1: Byte;
    VerifyId: Word;
    end;

    procedure TInSim.UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);//this is an event from indy
    var
    InSimPacket: TInSimPacket;
    RST_Packet: TRST_Packet;

    Begin
    AData.Position := 0;
    AData.ReadBuffer(InSimPacket, SizeOf(InSimPacket));
    AData.Position := 0;//reset the position back to the start of the packet

    if InSimPacket.Id = 'RST' then
    Begin
    AData.ReadBuffer(RST_Packet, SizeOf(RST_Packet));

    InSimPacket.Id := 'ACK'+#0;
    InSimPacket.Value := RST_Packet.VerifyId;

    UDPServer.SendBuffer(FHost, FHostPort, InSimPacket, SizeOf(InSimPacket));

    if Assigned(FOnRaceStart) then
    FOnRaceStart(RST_Packet);
    end;
    end;
    [/pascal]

    and this is how something is sent

    [pascal]type
    TSingleChar_Packet =packed record // send to LFS to simulate single character
    Id: Array[0..3] of Char; // SCH + zero
    C: Char; // key to press
    Flags: Byte; // bit 0 : SHIFT / bit 1 : CTRL
    Spare2: Byte;
    Spare3: Byte;
    end;
    procedure TInSim.SendChar(C: Char; Flags: Byte);
    var
    SingleChar_Packet: TSingleChar_Packet;

    Begin
    if not FConnected then
    Exit;

    SingleChar_Packet.Id := 'SCH' + #0;
    SingleChar_Packet.C := C;
    SingleChar_Packet.Flags := Flags;
    SingleChar_Packet.Spare2 := 0;
    SingleChar_Packet.Spare3 := 0;

    UDPServer.SendBuffer(FHost, FHostPort, SingleChar_Packet, SizeOf(SingleChar_Packet));
    end; [/pascal]

  5. #5

    Sending Dynamic Arrays with Indy

    Many thanks, I feel I understand it a bit better now and have adopted your approach as sending each update individually instead of as one big packet and it now appears to be working fine

    Thankyou again, you've been a great help!

  6. #6

    Sending Dynamic Arrays with Indy

    good good

  7. #7

    Re: Sending Dynamic Arrays with Indy

    Quote Originally Posted by andrew2110
    Hi. I've tried implementing the sending of dynamic arrays with Indy but recieve EAccessViolation error messages when I try to read the data from the server.
    The problem is, that a dynamic array (in Delphi) is just a pointer to a memory location. If you write athread.Connection.WriteBuffer(dynArray,sizeof(dyn Array)) you only transfer the 4 byte pointer address over the socket.

    You have to change your code a little bit:
    Code:
    Server Code:
    with areas[b.MID].players[i] do
     begin
      athread.Connection.WriteSmallInt(length(updates)); {Tell Client how many records they can expect to recieve }
    
      if length(updates)>0 then
       athread.Connection.WriteBuffer(updates[0],sizeof(updates[0])*length(updates)); { Write records }
    
      setlength(updates,0); {Set Records =0 }
     end;
     
    
    Client Code
     
       r:=idtcpclient1.ReadSmallInt(); { How Many Records Will We Recieve }
       
       setlength(up,r);
       if r>0 then 
        begin
          idtcpclient1.ReadBuffer(up[0],sizeof(up[0])*r);
        end;
    HTH

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •