보통 Socket이 Close될때 Client , Server간에 서로 close하겠다고
정보를 주고 받고 close하는게 정상적인 close인데...
Client에서 그런 정보를 보내지 못하고 끊어지면 위와같은 에러가 뜨는것 같습니다.
예를 들어 - 네트워크가 갑자기 끊어지거나
- Client프로그램이 갑자기 죽거나 등등의 현상이 발생하면
제대로된 해결은 아닌것 같은데..
그냥 Read부분에 try ~ catch 로 잡으시면 될듯 합니다.
try
{
int rslt=pStream->Read(Buffer, 100);
if( rslt== 0)
{
// 입력된 값이 없으면 종료
HIndex=fmServer->cbSocketHandle->Items->IndexOf(IntToStr(ClientSocket->SocketHandle));
fmServer->cbSocketHandle->Items->Delete(HIndex);
if(fmServer->cbSocketHandle->Items->Count==0)
{
fmServer->cbSocketHandle->Text="연결된 소켓 없음";
}
ClientSocket->Close();
}
fmServer->mbChat->Lines->Add(String(Buffer));
fmServer->BroadCastOut(String(Buffer));
fmServer->edtActiveThread->Text=fmServer->ServerSocket1->Socket->ActiveThreads;
}
catch(...)
{
// 입력된 값이 없으면 종료
HIndex=fmServer->cbSocketHandle->Items->IndexOf(IntToStr(ClientSocket->SocketHandle));
fmServer->cbSocketHandle->Items->Delete(HIndex);
if(fmServer->cbSocketHandle->Items->Count==0)
{
fmServer->cbSocketHandle->Text="연결된 소켓 없음";
}
ClientSocket->Close();
}
//------------------------------------------
구글신에 의지하여 TServerClientThread 예제 수십개를 보았지만
대부분 아래와 같은 처리하더군요
예외는 HandleException(); 으로...
void __fastcall TMyServerThread::ClientExecute()
{
while (!Terminated && ClientSocket->Connected) // make sure connection is active
{
try
{
TWinSocketStream *pStream = new TWinSocketStream(ClientSocket, 60000);
try
{
char buffer[50];
memset(buffer, 0, sizeof(buffer));
if (pStream->WaitForData(6000)) // give the client 60 seconds to start writing
{
if (pStream->Read(buffer, sizeof(buffer)) == 0)
ClientSocket->Close(); // if can't read in 60 seconds, close the connection
// now process the request
}
else
ClientSocket->Close();
}
__finally
{
delete pStream;
}
}
catch (...)
{
HandleException();
}
}
}
참고 하세요
http://dn.codegear.com/article/26276
http://topic.csdn.net/t/20060704/23/4860640.html
http://duketown.com/marcel/server.shtml
http://www.delmadang.com/cwb-bin/CrazyWWWBoard.exe?mode=read&num=754&page=49&db=dmdlec3&backdepth=3
http://topic.csdn.net/t/20020304/19/554711.html
http://delphi.newswhat.com/geoxml/forumhistorythread?groupname=borland.public.delphi.internet.winsock&messageid=40863a71@newsgroups.borland.com
http://www.ipc.hokusei.ac.jp/~z00104/delphi/thread.html
http://book.77169.org/ask1/ask100852.htm
http://forum.sources.ru/index.php?showtopic=159584
그럼..
짱구오빠 님이 쓰신 글 :
: Project SocketTread.exe raised exception class ESocketErrro with message 'Read error
: 64, 지정된 네트워크 이름을 더 이상 사용할 수 없습니다.'. Process stopped. Use Step or Run
: to Continue.
:
: 이런 메시지가 뜹니다.
:
: void __fastcall TServerSocketThread::ClientExecute(void)
: 함수에서
: if(pStream->WaitForData(300000))
: 에서 기다리다가 소켓으로 수신되면
: if(pStream->Read(Buffer, 100) == 0)를 처리한 후
: 정상적으로 처리된 후
: 다시
: if(pStream->WaitForData(300000)) 부분에서
: 수신을 기다려야 하는데
: if(pStream->Read(Buffer, 100) == 0)으로 넘아간 후
: pStream->Read 함수 처리시
: 위와같은 에러메시지가 나옵니다.
:
: 버퍼의 내용이 클리어가 않된건지...
:
: 아래 소스는 자료실에 있는 소켓쓰레드를 옮겨서 코딩한 겁니다.
: 무슨 에러인지 모르겠네요.
:
: 그리고 소켓서버의 멀티 쓰레드는 아래와 같이 코딩하면 되는건가요?
:
: 도와주세요.
:
:
:
: 소스 내용입니다.
:
: __fastcall TServerSocketThread::TServerSocketThread(bool CreateSuspended, TServerClientWinSocket * ASocket)
: : TServerClientThread(CreateSuspended, ASocket)
: {
: FreeOnTerminate=true;
: }
:
: void __fastcall TServerSocketThread::ClientExecute(void)
: {
: int HIndex;
: TWinSocketStream *pStream; // 소켓을 스트림으로 받음
: char Buffer[100];
:
: memset(Buffer, 0x00, sizeof(Buffer));
:
: while (!Terminated && ClientSocket->Connected)
: {
: pStream = new TWinSocketStream(ClientSocket, 60000);
: try
: {
: memset(Buffer, 0, sizeof(Buffer));
: if(pStream->WaitForData(300000))
: {
: // 5분간 입력이 없으면 종료
: if(pStream->Read(Buffer, 100) == 0)
: {
: // 입력된 값이 없으면 종료
: HIndex=fmServer->cbSocketHandle->Items->IndexOf(IntToStr(ClientSocket->SocketHandle));
: fmServer->cbSocketHandle->Items->Delete(HIndex);
: if(fmServer->cbSocketHandle->Items->Count==0)
: {
: fmServer->cbSocketHandle->Text="연결된 소켓 없음";
: }
:
: ClientSocket->Close();
: }
:
: fmServer->mbChat->Lines->Add(String(Buffer));
: fmServer->BroadCastOut(String(Buffer));
: fmServer->edtActiveThread->Text=fmServer->ServerSocket1->Socket->ActiveThreads;
: }
: else
: {
: HIndex=fmServer->cbSocketHandle->Items->IndexOf(IntToStr(ClientSocket->SocketHandle));
: fmServer->cbSocketHandle->Items->Delete(HIndex);
: if(fmServer->cbSocketHandle->Items->Count==0) fmServer->cbSocketHandle->Text="연결된 소켓 없음";
: ClientSocket->Close();
: }
: }
: __finally
: {
: delete pStream;
: }
: }
:
: //종료시 cbSocketHandle에서 ClientSocketHandle 삭제
: HIndex=fmServer->cbSocketHandle->Items->IndexOf(IntToStr(ClientSocket->SocketHandle));
: fmServer->cbSocketHandle->Items->Delete(HIndex);
: if(fmServer->cbSocketHandle->Items->Count==0)
: {
: fmServer->cbSocketHandle->Text="연결된 소켓 없음";
: }
: }
:
:
:
:
: //---------------------------------------------------------------------------
:
: // 쓰레드 외부에서 ClientSocketHandle값으로 CustomWinSocket을 생성하여 접속한 각 클라이언트로
: // 데이타를 날려준다. - BroadCast
: void __fastcall TfmServer::BroadCastOut(String SendString)
: {
: for(int i=0; i<cbSocketHandle->Items->Count;i++)
: {
: TCustomWinSocket *CustomWinSocket = new TCustomWinSocket(StrToInt(cbSocketHandle->Items->Strings[i]));
: CustomWinSocket->SendText(SendString);
: // delete CustomWinSocket;
: }
: }
:
:
: //---------------------------------------------------------------------------
:
: void __fastcall TfmServer::FormCreate(TObject *Sender)
: {
: ServerSocket1->Port=2000;
: ServerSocket1->Open();
: Sleep(100);
: Application->ProcessMessages();
: cntNum=0;
: }
: //---------------------------------------------------------------------------
: void __fastcall TfmServer::ServerSocket1ClientDisconnect(TObject *Sender,
: TCustomWinSocket *Socket)
: {
: mbStat->Lines->Add("사용자가 접속을 종료했습니다.");
: cntNum--;
: edtTotalNum->Text=cntNum;
: }
: //---------------------------------------------------------------------------
: void __fastcall TfmServer::ServerSocket1Accept(TObject *Sender,
: TCustomWinSocket *Socket)
: {
: mbStat->Lines->Add("사용자가 접속했습니다.");
: cntNum++;
: edtTotalNum->Text=cntNum;
: }
: //---------------------------------------------------------------------------
: void __fastcall TfmServer::ServerSocket1GetThread(TObject *Sender,
: TServerClientWinSocket *ClientSocket,
: TServerClientThread *&SocketThread)
: {
: // TServerClientThread 를 생성
: SocketThread = new TServerSocketThread(false, ClientSocket);
: }
: //---------------------------------------------------------------------------
: void __fastcall TfmServer::ServerSocket1GetSocket(TObject *Sender,
: int Socket, TServerClientWinSocket *&ClientSocket)
: {
: // SocketHandle을 저장
: cbSocketHandle->Items->Add(IntToStr(Socket));
: if(cbSocketHandle->Items->Count==1)
: {
: cbSocketHandle->Text=IntToStr(Socket);
: }
: }
: //---------------------------------------------------------------------------
: void __fastcall TfmServer::FormClose(TObject *Sender, TCloseAction &Action)
: {
: //Server Socket Close
: ServerSocket1->Close();
:
: //Memory Free
: Action = caFree;
: }
: //---------------------------------------------------------------------------
: void __fastcall TfmServer::ServerSocket1ThreadEnd(TObject *Sender,
: TServerClientThread *Thread)
: {
: edtActiveThread->Text=fmServer->ServerSocket1->Socket->ActiveThreads;
:
: }
: //---------------------------------------------------------------------------
: void __fastcall TfmServer::ServerSocket1ClientError(TObject *Sender,
: TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
: {
: mbStat->Lines->Add("사용자의 서버에 문제가 있습니다.");
: }