|
정확한 에러는 실행을 하지 않아 봐서 모르겠구요,
에러가 발생 가능한 코드에는 주석을 달아 봤습니다.
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 서버와 클라이언트는 수시로 접속을 끊었다가 접속하는 관계
:
: [현재나의상태]
: - 암울함
: - 미치고
: - 팔짝뛰겠슴
:
: 그럼 미리 감사드리며.. 현명한 답변이나.. 알기쉬운 예제를 부탁합니다.
:
|