Delphi Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
델파이 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
FreePascal/Lazarus
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
델마당
볼랜드포럼 광고 모집

델파이 Q&A
Delphi Programming Q&A
[15824] [질문]idTCPClient를 이용한 RecvThread 인데요. 구조가 잘못되었나요?
kivalan [openpgc] 2483 읽음    2016-11-17 14:10
안녕하세요.
idTCPClient를 이용한 RecvThread 인데요. 구조가 잘못되었나요?

목적 :
   서버는 1개의 세션밖에 허용하지 않기 때문에
   idTCPClient 한개로 TCP Connection을 유지한채 데이터를 보내고 받고 싶습니다.
   비동기 전송을 위해서 보내고 받는 부분을 분리해서
   수신부를 Thread로 만들어서 수신된 데이터를 Queue에 넣게 됩니다.
   수신시 락이나 cpu를 점유하지 않기 위해서 0.1초의 시간 단위로 데이터를 받습니다.

//수신 쓰레드.
type
  TTCPRecvThread = class(TThread)
  private
    FClient: TIdTCPClient;
    FData: string;
    FHostIP : String;
  protected
    procedure Execute; override;
  public
    constructor Create(AClient: TIdTCPClient); reintroduce;
  end;


// 구현부.
constructor TTCPRecvThread.Create(AClient: TIdTCPClient);
var
  sName : String;
begin
  inherited Create(True);
  sName := 'TCP RECV Thread:'+AClient.Host;
  self.NameThreadForDebugging(sName);
  FClient := AClient;
  FHostIP := AClient.Host;
end;


procedure TTCPRecvThread.Execute;
var
  t: cardinal;
//  idRecvBuf: TIdBytes;
  iRecvLen: integer;
  sRecvStr: AnsiString;

  i: integer;
  RecvByte: Byte;

begin

  try
    try
      FreeOnTerminate := True;
      frmMDRServer.Printlog('TTCPRecvThread Start;', False);

      while not Terminated do
      begin
        WaitForSingleObject(handle, 100);    //루프시 0.1의 딜레이를 가지고 돌기 위해.

        if gv_AppClose then   exit; //전역 프로그램 종료 변수.

         // 연결되지 않을때. 루프 대기를 위하여.
        if (not(Assigned(FClient))) or (not FClient.Connected) then
        begin
          WaitForSingleObject(handle, 100);
          Continue;
        end;

        FClient.IOHandler.CheckForDisconnect(True, True);

        // 버퍼 체크.
        if FClient.IOHandler.InputBufferIsEmpty then
        begin
          FClient.IOHandler.CheckForDataOnSource(100);
          if FClient.IOHandler.InputBufferIsEmpty then
            Continue;
        end;

        WaitForSingleObject(handle, 30);
        iRecvLen := FClient.IOHandler.InputBuffer.Size;

        sRecvStr := '';

        // H/W가 전송하는 방식이 시리얼에서 tcp로 바뀌어 혹시나 하는 마음에
        // 중간에 데이터가 있어도 조작하기 쉽도록 Byte단위처리함.
        for i := 1 to iRecvLen do
        begin
          RecvByte := FClient.IOHandler.ReadByte;
          if RecvByte = 13 then
            Continue;
          if RecvByte = 10 then // #10 단위의 문자열을 처리하게 됩니다.
          begin
               >함수전송처리Quue로Function(sRecvStr, FClient.Host); // 큐로 전송하여 처리함 Push pop시 CriticalSection거침.
               // 전송받은 문자열을 다른 쓰레드큐에서 직렬로 처리합니다. Message 처리도 같은 효과라고 생각합니다.
               sRecvStr := ''; // 문자열 초기화.
          end
          else
          begin
            sRecvStr := sRecvStr + Chr(RecvByte);
          end;
          if gv_AppClose then   exit;
        end;

        frmManForm.Printlog(format('Recv Msg : %s %d', [FClient.Host,iRecvLen]), False ); //메인폼에 로그큐에 넘김.

      end;

    except

      // raise;
      on E: EidException do // IdException
      begin
          // 예외가 발생한다면 출력하고.
          frmMDRServer.PrintLog('TTCPRecvThread E :' + FClient.Host + ' > ' +      E.Message, False); // 로그 큐에 메시지.
      end;
    end;
  finally
    frmMDRServer.PrintLog('TTCPRecvThread Exit;' + FClient.Host, False); // 로그 큐에 메시지.
    // 만약 종료한다면 접속을 끊고 나감.
    FClient.IOHandler.InputBuffer.Clear;
    FClient.Disconnect
    // Thread가 해제 될때 FClient에 할당된 idFTPCleint가 해제 되지 않도록 Nil로 세팅.
    FClient := nil;
  end;

end;



// 연결시 . ============================     

var
aRecvThread : TTCPRecvThread; //서버 1에 접속.
aRecvThread2 : TTCPRecvThread; //서버 2에 접속.
begin
    // .. 접속값.
    frmMainform.IdTCPClient_N1.Connect;

    if aRecvThread = nil then
    begin
      aRecvThread := TTCPRecvThread.Create(frmMainform .IdTCPClient_N1); // FClient 에 할당.
      aRecvThread .Resume;
   end;

    // .. 접속값.
    frmMainform.IdTCPClient_N2.Connect;

    if aRecvThread2 = nil then
    begin
      aRecvThread2 := TTCPRecvThread.Create(frmMainform .IdTCPClient_N2); // FClient 에 할당.
      aRecvThread2.Resume;
   end;

이런식으로 사용하고 있습니다.
이게 잘못된거 같아서 질문드립니다.

이게 잘못되어서 app.exe 는 응답없음 으로 빠지고.
델파이는  Ctrl+F2해서 중지하면. 다음 실행시 10048 소켓 Use 에러가 나서 PID는 죽은 건데.  Establish 커넥션이 남아 있어서
재부팅을 해야 합니다. ㅠ. tcpview  같은 것으로 죽여지지 않더라구요. Pid가 이미 없는 것이라서.
그래서 에러가 걸렸을때. CTRL+F2로 중지하지 말고. bds.exe를 죽여 버려야  이런게 안남아 있더라구요.

먼가 이 쓰레드가 죽을때..
잘못처리된듯 한데. 찍히지가 않네요.



+ -

관련 글 리스트
15824 [질문]idTCPClient를 이용한 RecvThread 인데요. 구조가 잘못되었나요? kivalan 2483 2016/11/17
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.