[转载]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或者是全局函数。

 

posted on 2015-10-16 14:30  maxpak  阅读(1575)  评论(0编辑  收藏  举报