• C++网络编程(二)客户端服务器程序


    这是一个基于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 ;

    C++网络编程(一)

  • 相关阅读:
    RDD的五个属性
    惰性求值的概念
    大数据shuffle的理解
    简单说明hadoop和hbase的异同
    Linux 下命令有哪几种可使用的通配符?分别代表什么含义?
    linux命令知识点复习
    >/dev/null 2>&1
    JAVA内存泄漏和内存溢出的区别和联系
    Linux各个目录的作用
    JVM标准参数-server与-client参数的区别
  • 原文地址:https://www.cnblogs.com/hlxs/p/3087036.html
Copyright © 2020-2023  润新知