這是一個基於windows的,用C++編寫的客戶端服務器程序,適合初學者,高手誤入.源碼必共享
思路是這樣的.啟動服務器,服務器啟動后會創建一個子線程,用於向客戶端發送信息.用一個死循環用於接收客戶端的請求,客戶端請求成功后,會將客戶端的連接保存到一個集合中,下面會詳細介紹這個保存客戶端連接的類.客戶端連接成功后,服務器會創建一個子線程用於接收客戶端的信息,客戶端同樣也會創建一個子線程接收服務器的信息.這樣客戶端和服務器就能進行通訊,如果有哪一方退出,另一方對應的接收數據的線程就會自動終止.
退出一個客戶端后,服務器對應的接收數據的線程自動終止.如下圖:
服務器保存客戶端連接的集合中會刪除對應的客戶端連接,由於這個刪除操作是在子線程中發生的,也就是說會有多個線程操作這個集合,那么針對這個集合的操作必須是線程安全的.保證線程安全的方法又很多,我的這篇博客《多線程編程--5種方法實現線程同步》介紹了5中方法實現線程同步,我這里用的是關鍵段,還有一點值得說明的是,保存客戶端連接的集合肯定只能有一份,我用一個類封裝了這個集合,這個類中的每個方法都是線程安全的,且只能有一個實例,這里用了比較暴力的方法,將相關的方法設為private,提供一個public的方法返回這個對象的一個靜態實例,唯一的一個實例。
保存客戶端連接的類如下:
//ClientList.h 存放客戶端的請求,只能有一個實例 #ifndef _CLIENTLIST_H_ #define _CLIENTLIST_H_ #include <vector> #include "CSocket.h" #include <assert.h> class CSocket; class ClientList { public : typedef vector<CSocket*>::iterator Iter; void Add(CSocket* socket); int Count() const; CSocket* operator[](size_t index); void Remove(CSocket* socket); Iter Find(CSocket* socket); void Clear(); static ClientList* GetInstance() { static ClientList instance; return &instance; } ~ClientList(); private: static CRITICAL_SECTION g_cs; static vector<CSocket*> _list; ClientList(); ClientList(const ClientList&); ClientList& operator=(const ClientList&); }; #endif
#include "ClientList.h" typedef vector<CSocket*>::iterator Iter; ClientList::ClientList() { InitializeCriticalSection(&g_cs);//初始化g_cs的成員 } ClientList::~ClientList() { DeleteCriticalSection(&g_cs);//刪除關鍵段 } void ClientList::Add(CSocket* socket) { if(socket!=NULL) { EnterCriticalSection(&g_cs);//進入關鍵段 _list.push_back(socket); LeaveCriticalSection(&g_cs);//退出關鍵段 } } int ClientList::Count() const { return _list.size(); } CSocket* ClientList::operator[](size_t index) { assert(index>=0 && index<_list.size()); return _list[index]; } void ClientList::Remove(CSocket* socket) { Iter iter=Find(socket); EnterCriticalSection(&g_cs);//進入關鍵段 if(iter!=_list.end()) { delete *iter; _list.erase(iter); } LeaveCriticalSection(&g_cs);//退出關鍵段 } Iter ClientList::Find(CSocket* socket) { EnterCriticalSection(&g_cs);//進入關鍵段 Iter iter=_list.begin(); while(iter!=_list.end()) { if(*iter==socket) { return iter; } iter++; } LeaveCriticalSection(&g_cs);//退出關鍵段 return iter; } void ClientList::Clear() { EnterCriticalSection(&g_cs);//進入關鍵段 for(int i=_list.size()-1;i>=0;i--) { delete _list[i]; } _list.clear(); LeaveCriticalSection(&g_cs);//退出關鍵段 } CRITICAL_SECTION ClientList::g_cs; vector<CSocket*> ClientList::_list ;