Q&A

  • [질문] TCP Server에서 Graph 그리기
idTCP Component를 이용해서 통신 프로그램을 만드는 중에 안풀리는 문제가 있어서 도움을 요청합니다.
통신프로그램을 시작한 단계에서 Indy Demo 프로그램의 도움을 많이 받고 있고, 그 중 idTCPDemo를 주로 이용하고 있습니다.
목표는 Client인 수십대의 의료기기에서 보내오는 신호를 Server로 받아 실시간으로 그래프를 그리는 것입니다.
테스트용으로 Sine함수 신호를 보내는 Client를 별도로 만들어서 동일 PC에서 구동하고 있습니다.

1. idTCPServer의 OnExecute에서 AThread.Connection.ReadBuffer로 Hexa 신호를 받으면 Decimal로 변환해서 WaveY에 넣고 WaveX를 1 증가시킵니다.
   WaveX, WaveY는 전역변수 Array 입니다.

2. WaveX, WaveY를 Memo Component에 표시하고
   지정된 PaintBox에 LineTo를 이용해서 WaveX, WaveY 위치로 그래프를 그려나갑니다.(DrawScreenWave procedure이용)
  
3. 문제는 Client를 늘려갈수록 그래프 그리는 기능이 불안정해지거나 아예 정지해 버린다는 것입니다. (숫자표시는 비교적 원활합니다)
   이 프로그램에서는 5개까지 테스트해보고 있는데 너무 차이가 많이 납니다. 실제로는 이보다 더 많은 데이터를 처리해야 하는데요.
   ReadBuffer의 처리에 걸리는 부하가 너무 많아서 그런가 싶어서 이 부분을 Synchronize 시키고 싶은데 여러가지 시도를 해봐도 잘 안되네요.
  
알맞은 방법을 알려주시면 고맙겠습니다.

참고로 프로그램(EX14.zip)을 첨부했습니다. Delphi 5에 Indy9.0을 사용하고 있습니다. (이 프로젝트가 잘 되어야 델파이 Upgrade가 가능한 터라서 마음이 급해지네요)
  

procedure TServerFrmMain.ServerExecute(AThread: TIdPeerThread);
var
  ActClient{, RecClient}: PClient;
  iClientCode : integer;
  HexaHigh, HexaLow : string;
  iHexaHigh, iHexaLow : integer;
begin
//  if (not AThread.Terminated) and AThread.Connection.Connected then   //if 1
//  begin
    AThread.Connection.ReadBuffer(CommBlock, SizeOf (CommBlock)) ;
    AThread.Connection.WriteBuffer(CommBlock, SizeOf(CommBlock), true);

    ActClient := PClient(AThread.Data);
    ActClient.LastAction := Now;  // update the time of last action

     Protocol.Lines.Add(TimeToStr(Time)+' : '+CommBlock.Command
                 +' from ' +CommBlock.SenderName + ' to ' + CommBlock.ReceiverName
                 + ' : '+CommBlock.DataHigh + ' - '+CommBlock.DataLow);

    if CommBlock.Command = 'SGNL' then begin   //if 2
      iClientCode := StrToInt(CommBlock.SenderName);

      HexaHigh := CommBlock.DataHigh;
      HexaLow := CommBlock.DataLow;
      iHexaHigh := StrToInt(HexaHigh);
      iHexaLow := StrToInt(HexaLow);
      WaveY[iClientCode] := iHexaHigh * 128 + iHexaLow;
      WaveX[iClientCode] := WaveX[iClientCode] + WaveXinc;

      if FlagWaveX[iClientCode] then begin
        DrawScreenWave(PaintBox[iClientCode], WaveX[iClientCode], WaveY[iClientCode]);
        Memo[2*iClientCode-1].Text := IntToStr(WaveX[iClientCode]);
        Memo[2*iClientCode].Text := IntToStr(WaveY[iClientCode]);
        if WaveX[iClientCode] > WaveScreenXmax then WaveX[iClientCode] := 0;
      end; // if
    end; // if 2
//  end; //if 1
end;
2  COMMENTS
  • Profile
    최용일 2010.06.01 02:22
    그래프 그리는 것 가지고 부하가 많이 걸릴것 같지는 않구요.
    Indy의 OnExecute가 쓰레드상에서 동작하는 것으로 알고 있습니다. 때문에 Memo 나 그래픽작업은 따로 빼시거나 Synchronize를 쓰셔야 합니다.
  • Profile
    이용벽 2010.06.01 17:47
    답변 감사드립니다.
    말씀하신대로 그래프 그리는 부분을 별도 Procedure로 해서 Synchronize를 적용해보았습니다.
    다소 나아지기는 했지만 만족스럽지는 않네요.

    AThread.Connection.ReadBuffer(CommBlock, SizeOf (CommBlock)) ;
    이부분에 Synchronize를 적용해보고 싶은데 변수가 전달이 안된다고 하네요. 어떤 방법이 있을까요.
    힌트를 주시면 고맙겠습니다.


    procedure TServerFrmMain.ServerExecute(AThread: TIdPeerThread);
    var
    ActClient{, RecClient}: PClient;
    begin
    // if (not AThread.Terminated) and AThread.Connection.Connected then //if 1
    // begin
    AThread.Connection.ReadBuffer(CommBlock, SizeOf (CommBlock)) ;
    AThread.Connection.WriteBuffer(CommBlock, SizeOf(CommBlock), true);

    ActClient := PClient(AThread.Data);
    ActClient.LastAction := Now; // update the time of last action

    Protocol.Lines.Add(TimeToStr(Time)+' : '+CommBlock.Command
    +' from ' +CommBlock.SenderName + ' to ' + CommBlock.ReceiverName
    + ' : '+CommBlock.DataHigh + ' - '+CommBlock.DataLow);

    AThread.Synchronize(DataProcess);


    // end; //if 1
    end;

    procedure TServerFrmMain.DataProcess;
    var
    iClientCode : integer;
    HexaHigh, HexaLow : string;
    iHexaHigh, iHexaLow : integer;
    begin
    if CommBlock.Command = 'SGNL' then begin //if 2
    iClientCode := StrToInt(CommBlock.SenderName);

    HexaHigh := CommBlock.DataHigh;
    HexaLow := CommBlock.DataLow;
    iHexaHigh := StrToInt(HexaHigh);
    iHexaLow := StrToInt(HexaLow);
    WaveY[iClientCode] := iHexaHigh * 128 + iHexaLow;
    WaveX[iClientCode] := WaveX[iClientCode] + WaveXinc;

    if FlagWaveX[iClientCode] then begin
    DrawScreenWave(PaintBox[iClientCode], WaveX[iClientCode], WaveY[iClientCode]);
    Memo[2*iClientCode-1].Text := IntToStr(WaveX[iClientCode]);
    Memo[2*iClientCode].Text := IntToStr(WaveY[iClientCode]);
    if WaveX[iClientCode] > WaveScreenXmax then WaveX[iClientCode] := 0;
    end; // if
    end; // if 2
    end;