多客戶端服務器網絡編程

這是一個基於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 ;

發佈了33 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章