1. 程式人生 > >MFC基於select模型的套接字類之伺服器(8)

MFC基於select模型的套接字類之伺服器(8)

4 停止伺服器

CTCPSocket_Server類新增訪問許可權為public的成員函式StopServer()。在該函式中主要完成的工作是關閉“2.3 StartServer()函式”中提到了用於接受客戶端連線的執行緒和用於接收客戶端資料的執行緒。

4.1 結束接受客戶端連線的執行緒

2.3 StartServer()函式”中提到,該執行緒由CTCPSocket_Server類的成員變數m_acceptthread_alive來控制。當該變數的值是false時,執行緒函式中的while()迴圈將退出,結束執行緒。

StopServer()函式中,首先將m_acceptthread_alive

設定為false

m_acceptthread_alive = false;
接下來使用WaitForSingleObject()函式等待該執行緒結束。
WaitForSingleObject(m_acceptthread_handle, 1000);
WaitForSingleObject()函式的第一個引數指定了等待執行緒的控制代碼,第二個引數表示等待的時間,單位為毫秒。在等待了1秒鐘之後,呼叫GetExitCodeThread()函式判斷指定的執行緒是否結束,如果未結束,則呼叫TerminateThread()函式強行退出。
DWORD exitcode_thread = 0;
if (!GetExitCodeThread(m_acceptthread_handle, &exitcode_thread) || exitcode_thread == STILL_ACTIVE)
{
TerminateThread(m_acceptthread_handle, exitcode_thread);
}
CloseHandle(m_acceptthread_handle);
m_acceptthread_handle = NULL;
GetExitCodeThread()函式的第一個引數表示指定執行緒的控制代碼;第二個引數是執行緒的退出碼。如果指定的執行緒已經結束,則該函式的返回值是非零,如果執行緒未結束,則退出碼exitcode_thread的值是STILL_ACTIVE,如果函式執行失敗,則返回值為0。在將執行緒退出之後,將呼叫CloseHandle()函式關閉執行緒控制代碼,並且將執行緒控制代碼清空。

4.2 關閉監聽連線的套接字

2.3.5 建立新執行緒接收資料”中提到,可以“優雅”關閉套接字,也可以“強行”關閉套接字。使用“優雅”的方式關閉套接字時,在呼叫closesocket()函式之前,需要呼叫shutdown()

函式來禁止套接字的傳送和接收動作。該函式的格式為

int shutdown(SOCKET s, int how);
其中,引數s指定了要指定動作的套接字;how表示禁止套接字的什麼動作,該引數是SD_RECEIVE時,表示禁止套接字接收資料,SD_SEND表示禁止套接字傳送資料,SD_BOTH表示進位制套接字收發資料。
shutdown(m_socket_listen, SD_BOTH);
closesocket(m_socket_listen);
m_socket_listen = NULL;

4.3結束接收客戶端資料的執行緒

用於接收客戶端資料的執行緒控制代碼都儲存在2.3.6 建立接收客戶端資料的執行緒”中介紹的CTCPSocket_Server類的m_recvdata_threadhandle_array中。

for (int i = 0; i < MAX_CONNECTION; ++i)
{
if (m_clientconnectflag_array[i])
{
m_clientconnectflag_array[i] = false;
WaitForSingleObject(m_recvdata_threadhandle_array[i], 500);
if (!GetExitCodeThread(m_recvdata_threadhandle_array[i], &exitcode) || exitcode==STILL_ACTIVE)
{
TerminateThread(m_recvdata_threadhandle_array[i], exitcode);
}
CloseHandle(m_recvdata_threadhandle_array[i]);
m_recvdata_threadhandle_array[i] = NULL;
         .............
          }
   }
以上程式碼的作用是結束m_recvdata_threadhandle_array中儲存的控制代碼對應的執行緒。結束執行緒的方法與“4.1 結束接受客戶端連線的執行緒”中提到的方法相同。

4.4 優雅關閉與客戶端通訊的套接字

在結束了接收客戶端資料的執行緒之後,在4.3結束接收客戶端資料的執行緒”中程式碼的for迴圈中,繼續優雅關閉與客戶端通訊的套接字。優雅關閉套接字的方法與“4.2 關閉監聽連線的套接字”中提到的方法相同。

shutdown(m_clientsocket_array[i], SD_BOTH);
closesocket(m_clientsocket_array[i]);
m_clientsocket_array[i] = NULL;