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

C++빌더 Q&A
C++Builder Programming Q&A
[13469] Re:[질문] 블록킹모드 소켓(인디)을 쓰레드로 읽을때...(indy)
이경문 [gilgil] 1299 읽음    2001-12-08 03:23
정확한 에러는 실행을 하지 않아 봐서 모르겠구요,
에러가 발생 가능한 코드에는 주석을 달아 봤습니다.
FormClose가 되어서 관련 메모리들이 해제되었는데도
thread는 아직 종료가 되지 않아서
        Form1->MessageHandler(Message, NULL);
여기에서 에러가 발생할 확률이 가장 높은 것으로 보입니다(즉 Form객체는 free되었는 데 Form1을 access하려구 해서).

thread->Terminate() 했다고 해서 thread가 종료되는 것은 아니거든요.
Terminate() function은 exit condition flag만 setting하는 것이지 thread가 종료되는 것은 아니랍니다.
일단 FormClose에서 clientSocket->Disconnect()를 호출하여 thread가 빨리 종료되도록 하는 것도 중요합니다.



#pragma resource "*.dfm"
TForm1 *Form1;
static int loopCnt = 0;
//---------------------------------------------------------------------------
__fastcall TmyReadThread::TmyReadThread(): TThread(TRUE)
{
    FreeOnTerminate = true;
    Resume();
}
//---------------------------------------------------------------------------

void __fastcall TmyReadThread::Execute()
{
    while( !Terminated )
    {
        // 쓰레드가 혼자 설치지 못하게 하기위해서.. Sleep추가
        ::Sleep(200);

        char Message[BUFF_SIZE];
        char M_SIZE [3] = { '\0', '\0', '\0' };

        bool isF = true;

        for(int loop=0; !Terminated; loop++)
        {
            char charBuff;
            Form1->clientSocket->ReadBuffer((void *) &charBuff, sizeof(charBuff));
            // ******************************************
            // thread 예의상 block이 될만한 function뒤에는 반드시 if terminated... 를 넣어 줍시다
            if Termnated then break;
            // ******************************************

            Message[loop] = charBuff;

            if ( loop < 2)
            {
                M_SIZE[loop] = charBuff;
            }
            if ( isF )
            {
                isF = false;
            }
            if( loop >= 2 && (loop+1) == * ( short int* ) M_SIZE )   break;
        }

        // 데이터를 읽었으므로 적당한 처리를 한다..
        // 처리내용은 그냥 메모컴포넌트에 읽은 정보중 일부를 출력해준다.
        // ******************************************
        // 이 경우 FormClose가 불렸는지 아닌지를 확인해 봅시다.
        Form1->MessageHandler(Message, NULL);
        // ******************************************
    }
}

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    clientSocket->Host = "localhost";
    clientSocket->Connect();

    SendMemo->Lines->Add ( "PP Connect...." );
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
    for(int loop=0; loop<500; loop++)
    {
        struct basic_int mystruct;
        mystruct.cmd = 101;
        mystruct.number = loop;
        mystruct.size = sizeof(mystruct);

        clientSocket->WriteBuffer(&mystruct, sizeof(mystruct), true);
    }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::clientSocketConnected(TObject *Sender)
{
    ReadThread = new TmyReadThread();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::MessageHandler(char* Msg, TIdPeerThread *AThread)
{
    char Message[BUFF_SIZE];
    memcpy(Message, Msg, BUFF_SIZE);

    //struct basic_struct basicstruct = * ( ( basic_struct * ) Message );
    struct basic_int mystruct = * ( ( basic_int * ) Message );

    //switch( mystruct.cmd )
    //{
    //}
    ReciveMemo->Lines->Add ( (String) mystruct.number );
}
//---------------------------------------------------------------------------
// 클라이언트 소켓의 버퍼를 확실히 클리어시켜준다.
void __fastcall TForm1::clearData()
{
    try
    {
        loopCnt++;
        clientSocket->ExtractXBytesFromBuffer(1);
    }
    catch(...)
    {
// **************************************************
// thread가 종료되면 ReadThread의 값은 NULL일까요?
// 제 생각에는 아닌 것 같은데요...
        if ( ReadThread ) ReadThread->Terminate();
// **************************************************

        return;
    }
// **************************************************
// 이건 뭐져? recursion을 부르는 구조이네요... unreachable code같은데...
    clearData();
// **************************************************
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
    // **************************************************
    // 요걸 불러야 위의 thread 부분이 빨리 종료됩니다.
    clientsocket->Disconnect();
    // **************************************************

    clearData();

    // ShowMessage는 클라이언트 소켓에 남아있던 데이터의 바이트수 +1 을 알려줍니다.
    // 이상하케 ShowMessage를 띄우면 에러없고 Sleep은 에러가 납니다.
    //::Sleep(2000);
    ShowMessage(loopCnt);

    if ( ReadThread   ) ReadThread->Terminate();
}
//---------------------------------------------------------------------------



헬프미 님이 쓰신 글 :
: 안녕하세요?
:
: 혼자힘으로 해 볼려고 많이 노력해 봤는데.. 안되는군요.
: 고수님들의 조언을 바랍니다.
: 제가 문제를 가지고 있는 파일을 첨부합니다.
:
: [상황]
: - 인디 컴포넌트를 사용하는 C/S프로그램
: - 인디 클라이언트 소켓으로 데이터를 읽을때는 쓰레드를 이용
: - 데이터의 흐름은 클라이언트->서버->클라이언트 (일종의 에코기능)
: - 클라이언트가 서버로 데이터를 전송할때는 for문을 써서 50개 이상의 데이터를 날림
: - 서버는 OnExcute이벤트가 떨어질때 클라이언트로 부터 도착한 메시지를 읽음 그리고 클라이언트로 재전송
: - 클라이언트는 쓰레드를 통해서 항상 소켓을 감시하다가 도착한 메시지를 읽음
:
: [문제점]
: - 클라이언트가 자신이 for문을 통해 전송한 메시지를 모두 에코받고 종료하면 => 아무문제 없슴
: - 클라이언트가 자신이 보낸 메시지를 모두 받지 못하고 종료하면 => 블루스크린 T_T
:
: [나름대로 힌트]
: - 쓰레드를 종료하기전에 클라이언트 소켓의 버퍼를 완전히 지운다음 ShowMessage("");를 호출하니 아무런 문제없었는데.. ShowMessage코드가 없으니까 에러가 뜨는군요. ShowMessage말고 ::Sleep을 해봤는데.. 여전히 에러..
:
: [나의목표]
: - 인디를 사용하여 1:N관계의 P2P엔진을 구현함
: - P2P 서버와 클라이언트는 수시로 접속을 끊었다가 접속하는 관계
:
: [현재나의상태]
: - 암울함
: - 미치고
: - 팔짝뛰겠슴
:
: 그럼 미리 감사드리며.. 현명한 답변이나.. 알기쉬운 예제를 부탁합니다.
:

+ -

관련 글 리스트
13434 [질문] 블록킹모드 소켓(인디)을 쓰레드로 읽을때...(indy) 헬프미 1134 2001/12/06
13469     Re:[질문] 블록킹모드 소켓(인디)을 쓰레드로 읽을때...(indy) 이경문 1299 2001/12/08
13443     [참고] 그냥 참고만 하세요! 홍지곤 868 2001/12/07
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.