zoukankan      html  css  js  c++  java
  • [转载]socket下server端支持多客户端并发访问简单实现

    /*Author:  wainiwann

    *Source: 博客园 http://www.cnblogs.com/wainiwann

    *Remarks:  转载请说明出处!!!

    */

    感觉很不错,可以学习一下。

    socket下server端支持多客户端并发访问简单实现

    server端开启之后始终有两个线程在处理连接请求,一个是只负责客户端的请求连接的(这里是只针对TCP协议),当客户端connect的时候 记录当前客户端连接存放到数据组中当中,而这个数组声明为全局成员,其实在线程内处理外部成员的话,也没必要非要用静态或者全局成员,今天听经理说也可以 在创建该线程时,把某类的this指针传递过去,同样好像也可以访问public成员的,具体行不行,还没试不过真的是不错的方法。要知道很多在项目很避 讳使用全局的东西,甚至有的公司直接不让使用全局的东西。这里扯的有点远了。

    另外一个同步允许的线程就是对accept记录的数组进行操作,依次处理各个客户端请求通信和状态监控等,当数组内socket成员不为空时记录当前索引然后在create发送或者获取线程处理函数并发响应多个客户端的连接请求通信

    加载套接字库:

    BOOL TcpServer::InitSocket()
    {
        WORD wVersionRequested;
        WSADATA wsaData;
        int err;
        wVersionRequested = MAKEWORD( 1, 1 );
        err = WSAStartup( wVersionRequested, &wsaData );
        if ( err != 0 ) 
        {
            return FALSE;
        }
    
        if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) 
        {
            WSACleanup( );
            return FALSE;
        }
    
        //创建套接字
        //SOCKET m_socket=socket(AF_INET,SOCK_STREAM,0);
    
        
        return TRUE;
    }

     开启执行Accept线程处理函数:

    BOOL TcpServer::SatartServer()
    {
        //创建线程
        HANDLE hThread = CreateThread(NULL,0,ThreadProc_Accept,NULL,0,NULL);
        //关闭该接收线程句柄,释放引用计数
        CloseHandle(hThread);
    
        return TRUE;
    }

    线程处理函数:

    DWORD WINAPI TcpServer::ThreadProc_Accept(LPVOID lpParameter)
    {
        int len = sizeof(SOCKADDR);
        int err;
        m_socket=socket(AF_INET,SOCK_STREAM,0);
        if (m_socket == INVALID_SOCKET)
        {
            AfxMessageBox(_T("套接字创建失败!"));
            return FALSE;
        }
    
        SOCKADDR_IN addrSrv;
        addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
        addrSrv.sin_family=AF_INET;
        addrSrv.sin_port=htons(8099);
    
        err = bind(m_socket,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));    //绑定本地端口
        if (err==SOCKET_ERROR)
        {
            closesocket(m_socket);
            AfxMessageBox(_T("绑定失败!"));
            return FALSE;
        }
        listen(m_socket,10);//开启监听
    
        //创建线程
        HANDLE hThread = CreateThread(NULL,0,ThreadProc_Select,NULL,0,NULL);
        //关闭该接收线程句柄,释放引用计数
        CloseHandle(hThread);
    
        while (TRUE)
        {
            m_CliSocketArr[m_ToolConn++] = accept(m_socket,(SOCKADDR*)&addrSrv,&len);
        }
        return 0;
    }

     同时在该线程函数内创建处理客户端数组的线程处理函数: 

    DWORD WINAPI TcpServer::ThreadProc_Select(LPVOID lpParameter)
    {
        int recvflag=0;
    
        fd_set    fdread;                //读集fdread
        int        ret;                //查看某个套接字的状态
        struct timeval tv = {1,0};    //实例化timeval变量
    
        while (TRUE)
        {
            //判断当前连接数是否为 0
            if (m_ToolConn == 0)
            {
                Sleep(50);
                continue;
            }
    
            FD_ZERO(&fdread);
            for (int i = 0;i < m_ToolConn;i++)
            {
                FD_SET(m_CliSocketArr[i],&fdread);
            }
            ret = select(0,&fdread,NULL,NULL,&tv);
            if (ret == 0)
            {
                continue;
            }
            for (int i =0;i<m_ToolConn;i++)
            {
                if (FD_ISSET(m_CliSocketArr[i],&fdread))
                {
                    ret = recv(m_CliSocketArr[i],(char*)&recvflag,sizeof(int)+1,0);
                    if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
                    {
                        closesocket(m_CliSocketArr[i]);
                        if (i < m_ToolConn-1)
                        {
                            m_CliSocketArr[i] = m_CliSocketArr[--m_ToolConn];
                        }else
                        {
                            --m_ToolConn;
                        }
    
                    }else
                    {
                        INDEX * inx = new INDEX;
                        inx->flag  = recvflag;
                        inx->index = i;
    
                        //创建线程
                        HANDLE hThread = CreateThread(NULL,0,ThreadProc_Response,(LPVOID)inx,0,NULL);
                        //关闭该接收线程句柄,释放引用计数
                        CloseHandle(hThread);
    
                    }
                }//if
            }//for
        }//while
    
        return 0;
    }

    下面就是一次创建线程并发处理客户端请求线程处理函数:

    DWORD WINAPI TcpServer::ThreadProc_Response(LPVOID lpParameter)
    {
        int ix = ((INDEX*)lpParameter)->index;
        int flag = ((INDEX*)lpParameter)->flag;
    
        delete lpParameter;
    
        if (flag == 1)
        {
            //.............................
            unsigned char sendBuffer[1024] = {'a'};
            send(m_CliSocketArr[ix],(char*)sendBuffer,sizeof(sendBuffer)+1,0);
        }
    
        return 0;
    }

    线程处理函数在定义时,要设置为static或者是全局函数。

  • 相关阅读:
    JS&和&&-T
    PHP Xdebug
    PHP非对称加密
    JavaScript:弹框输出
    JavaScript:函数闭包
    JavaScript:函数
    JavaScript:正则表达式 & 日期对象
    JavaScript: Math数学对象 & Number对象
    JavaScript: 数组
    JavaScript: 常用字符串API
  • 原文地址:https://www.cnblogs.com/maxpak/p/4885219.html
Copyright © 2011-2022 走看看