Q&A

  • 가변 Data전송
일정지 않은 크기의 String문자를 글자수 많큼 Socket으로 보낼 수 있는지요?
데이터 구조는 다음과 같습니다.

|글자수| String문자 |

이런식으로 한다면... String문자를 어떻게 구성(선언) 해야 하는지....
저의 질문은 바로 이것인데요...

동적배열을 써도.. 해결이 안됩니다..
도와주세요.. ㅠㅠ


아참..

TLCS_REQ_PORT_DIAL = Record
     slot : byte;
     port : byte;
     channel : byte;  // reserved : 0
     digitLen : byte;
     digitString : array of char;
end;

다음과 같은 구조로 저장해서 buffer에 move 한다음 Socket으로 전송했습니다.
5  COMMENTS
  • Profile
    이중철 2003.02.19 20:06
    TLCS_REQ_PORT_DIAL = Record
         slot : byte;
         port : byte;
         channel : byte;  // reserved : 0
         digitLen : byte;
         digitString : array of char;
    end;
    이거 이렇게 해보았자 맨 마지막 필드는 실제 어레이가 아니라
    그냥 포인터에요 즉 4바이트만 있어요
    그리고 나중에 Setlength 해봤자 해당 레코드 밑에 메모리설정
    되는것이 아닙니다.
    이와같을 경우 몇가지 방법이 있는데

    1. 헤더와 데이타를 나누고 나중에 합치는 스타일;
       - 레코드내에 가변필드가 많을경우
    2. 가변필드가 맨마지막에 있고 어느정도 한정되어 있을 경우는
        맨마지막 필드를 Max(위에보니 255가 끝이네요)까지 설정하고
        전송시 전송바이트 조절

    2번만 이야기 할께요
    type
    LCS_REQ_PORT_DIAL_HEADER =  Record
         slot : byte;
         port : byte;
         channel : byte;  // reserved : 0
         digitLen : byte;
    end;
    LCS_REQ_PORT_DIAL =  Record
         header : LCS_REQ_PORT_DIAL_HEADER;
         digitString : array[0..255] of char;
    end;
    .....
    var
      SendRecord : LCS_REQ_PORT_DIAL;
    begin

      TCPClient1.WriteBuffer(SendRecord, sizeof(SendRecord.header) + SendRecord.header.digitLen, .....);
    end;

    이런식이 나을듯 하네요.

  • Profile
    이중철 2003.02.19 20:14
    TLCS_REQ_PORT_DIAL = Record
         slot : byte;
         port : byte;
         channel : byte;  // reserved : 0
         digitLen : byte;
         digitString : array[0..255] of char;
    end;

    이렇게 설정하고
    TCPClient1.WriteBuffer(SendRecord, SendRecord.digiylen + 4..)
    이런식으로 하면 안되요..


  • Profile
    진돌 2003.02.19 23:23
    답변주셔서 정말 감사드립니다..
    죄송합니다만... 다시 질문 드려요.... (ㅠㅠ)

    그런데 제가 하고자하는 부분은 조금 복잡해서 중철님이 알려주신 방법은 적용이 안될거 같아요..
    구조를 간단히 말씀드리면..

    --------------------------------------
    |                  prim  (REQ)                    |
    --------------------------------------
    |                          id                          |
    --------------------------------------
    |           elemLen (아래의 길이)            |
    --------------------------------------
    |   slot    |   por t   | channel | digitLen |
    --------------------------------------     1
    |            digitString (가변길이)              |
    --------------------------------------
    |   slot    |   por t   | channel | digitLen |
    --------------------------------------     2
    |            digitString (가변길이)              |
    --------------------------------------
                               ...
    --------------------------------------
    |   slot    |   por t   | channel | digitLen |
    --------------------------------------     n
    |            digitString (가변길이)              |
    --------------------------------------


    위에 처럼.. 여러개의 digitString이  붙게 됩니다..
    소스구조는 다음과 같습니다..


      TLCS_REQ_PORT_DIAL = Record
          slot : byte;
          port : byte;
          channel : byte;  
          digitLen : byte;
          digitString : array of char;            // >>>>>>>>>>>>>> 이부분...   array[0..9] of char 이런식으로 하면 되지만.. 가변길이 적용 안됨 항상 10 byte
      end;

      TLCS_REQ_MSG_HD = Record
          prim : Integer;
          svcId : Integer;
          elem : Integer;
          lcs_req_port_dial : array[0..59] of TLCS_REQ_PORT_DIAL;        // Dial이 60개 까지 설정 가능...
      end;


    소켓 전송시.... 소스

    lcs_req_msg_hd : TLCS_REQ_MSG_HD;
    move(lcs_req_msg_hd, buffer, SizeOf(lcs_req_msg_hd));
    SendBuffer(ip_addr, 9992, buffer, SizeOf(lcs_req_msg_hd));


    이럴땐 어떤 방법을 해야 하는지요..
    시간나시면 답변줌 부탁드립니다..
  • Profile
    이중철 2003.02.20 00:41
    unit Unit1;

    interface

    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;

    type
      TLCS_REQ_MSG_HD = Record
        prim : Integer;
        svcId : Integer;
        elem : Integer;
      end;
      TLCS_REQ_PORT_DIAL = packed Record
        slot : byte;
        port : byte;
        channel : byte;
        digitLen : byte;
        digitString : array[0..0] of byte;
      end;
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
        m_Buff : TByteArray;
        m_BuffPoint : Integer;
      public
        { Public declarations }
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.Button1Click(Sender: TObject);
    var
      PHeader : ^TLCS_REQ_MSG_HD;
      PData : ^TLCS_REQ_PORT_DIAL;
      i , j, r : integer;
    begin
      m_BuffPoint := 0;
      PHeader := @m_Buff[m_BuffPoint];
      PHeader^.prim := 1234; //임의로 했음
      PHeader^.svcId := 3452; //임의로 했음
      PHeader^.elem := 34; //임의로 했음
      m_BuffPoint := sizeof(TLCS_REQ_MSG_HD);
      for i := 0 to PHeader^.elem - 1 do
      begin
        PData := @m_Buff[m_BuffPoint];
        PData^.slot := $FF; //임의로 했음
        PData^.port := $FF; //임의로 했음
        PData^.channel := $FF; //임의로 했음
        r := random(254) + 1; //임의로 했음
        PData^.digitLen := r;
        for j := 0 to r - 1 do
          PData^.digitString[j] := j;
        m_BuffPoint := m_BuffPoint + r + 4;
      end;
      SendBuffer(ip_addr, 9992, m_Buff, m_BuffPoint);
    end;

    end.

    장점은 Overhead가 전혀 없다는 거에요.
    폼 처음띄울때 한번 메모리 잡고 그 이후 메모리 할당도 없고
    Move할 필요도 없고
    님께서 정의하신 스트럭쳐를 보면 메모리 클리어도 필요 없을듯
    합니다 그러니 Clear(FillChar)도 필요없고
    저도 쓸때는 Clear 안하고 썼어요 데이타가 다 들어가 있어서 ^^

    참 총 패킷사이즈 제한되어 있으면 TByteArray 이거 쓰지마시고
    그냥 배열정의해 주세요
    TByteArray 이넘은 3만2천바이트 이니..

    이해될지 잘 모르겠네요..
    일단 Range Check Option을 Disable 해주시고 컴파일 해주세요

  • Profile
    진돌 2003.02.20 04:16
    워낙 허접해서 포인터로 하지 않았는데
    생각보다 간단하군요...  ^^

    정말 감사드립니다..