/** * 接受用戶端連接 */ DWORD __stdcall AcceptThread(void* pParam) { SOCKET sAccept; //接受用戶端連接的通訊端 sockaddr_in addrClient; //用戶端SOCKET地址 for (;bServerRunning;) //伺服器的狀態 { memset(&addrClient, 0, sizeof(sockaddr_in)); //初始化 int lenClient = sizeof(sockaddr_in); //地址長度 sAccept = accept(sServer, (sockaddr*)&addrClient, &lenClient); //接受客戶請求 if(INVALID_SOCKET == sAccept ) { int nErrCode = WSAGetLastError(); if(nErrCode == WSAEWOULDBLOCK) //無法立即完成一個非阻擋性通訊端操作 { Sleep(TIMEFOR_THREAD_SLEEP); continue;//繼續等待 }else { return 0;//執行緒退出 } } else//接受用戶端的請求 { /* 呼叫建構子進行客戶端節點的初始化。 將此節點加入鏈表clientlist。 為鏈表clientlist內的每個客戶端節點取得鏈表clientlist (藉由客戶端節點的GetClientList()函式) */ CClient *pClient = new CClient(sAccept, addrClient, seq++, csClientList); EnterCriticalSection(&csClientList); clientlist.push_back(pClient); LeaveCriticalSection(&csClientList); pClient->StartRuning(); CLIENTLIST::iterator iter = clientlist.begin(); for(iter; iter != clientlist.end();) { CClient *pTemp = (CClient*)*iter; pTemp->GetClientList(clientlist); ++iter; } } } return 0;//執行緒退出 }
/** * 清理資源 */ DWORD __stdcall HelperThread(void* pParam) { for (;bServerRunning;)//伺服器正在運行 { /* 清理已經斷開連接之客戶的記憶體空間。 如果有客戶斷開連線,則必須重新 為鏈表clientlist內的每個客戶端節點取得鏈表clientlist (藉由客戶端節點的GetClientList()函式) */ EnterCriticalSection(&csClientList); CLIENTLIST::iterator iter = clientlist.begin(); BOOL isErase = false; for (iter; iter != clientlist.end();) { CClient *pClient = (CClient*)*iter; //如果用戶端的連接還存在,則斷開連接,執行緒退出 if (!(pClient->IsConning())) { iter = clientlist.erase(iter); //將刪除 isErase = true; //設定Erase flag } else{ ++iter; // 沒有消除的話在++ } } if(isErase) // 如果有移除 將其他clientlist更新 { iter = clientlist.begin(); for(iter; iter != clientlist.end();) { CClient *pTemp = (CClient*)*iter; pTemp->GetClientList(clientlist); delete pTemp; ++iter; } } LeaveCriticalSection(&csClientList); Sleep(TIMEFOR_THREAD_HELP); } //伺服器停止工作 if (!bServerRunning) { //斷開每個連接,執行緒退出 EnterCriticalSection(&csClientList); CLIENTLIST::iterator iter = clientlist.begin(); for (iter; iter != clientlist.end();) { CClient *pClient = (CClient*)*iter; //如果用戶端的連接還存在,則斷開連接,執行緒退出 if (pClient->IsConning()) { pClient->DisConning(); } ++iter; } //離開臨界區 LeaveCriticalSection(&csClientList); //給連接用戶端執行緒時間,使其自動退出 Sleep(TIMEFOR_THREAD_SLEEP); //進入臨界區 EnterCriticalSection(&csClientList); //確保為每個用戶端分配的記憶體空間都回收。 //如果不加入while這層迴圈,可能存在這樣的情況。當pClient->IsExit()時,該執行緒還沒有退出。 //那麼就需要從鏈表的開始部分重新判斷。 while ( 0 != clientlist.size()) { iter = clientlist.begin(); for (iter; iter != clientlist.end();) { CClient *pClient = (CClient*)*iter; if (pClient->IsExit()) //用戶端執行緒已經退出 { clientlist.erase(iter++); //刪除節點 delete pClient; //釋放記憶體空間 pClient = NULL; }else{ iter++; //指針下移 } } //給連接用戶端執行緒時間,使其自動退出 Sleep(TIMEFOR_THREAD_SLEEP); } LeaveCriticalSection(&csClientList);//離開臨界區 } clientlist.clear(); //清空鏈表 SetEvent(hServerEvent); //通知主執行緒退出 return 0; }