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

    /*

    *Author:  wainiwann

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

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

    */

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

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

    加载套接字库:

    复制代码
     1 BOOL TcpServer::InitSocket()
     2 {
     3     WORD wVersionRequested;
     4     WSADATA wsaData;
     5     int err;
     6     wVersionRequested = MAKEWORD( 1, 1 );
     7     err = WSAStartup( wVersionRequested, &wsaData );
     8     if ( err != 0 ) 
     9     {
    10         return FALSE;
    11     }
    12 
    13     if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) 
    14     {
    15         WSACleanup( );
    16         return FALSE;
    17     }
    18 
    19     //创建套接字
    20     //SOCKET m_socket=socket(AF_INET,SOCK_STREAM,0);
    21 
    22     
    23     return TRUE;
    24 }
    复制代码

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

    复制代码
    1 BOOL TcpServer::SatartServer()
    2 {
    3     //创建线程
    4     HANDLE hThread = CreateThread(NULL,0,ThreadProc_Accept,NULL,0,NULL);
    5     //关闭该接收线程句柄,释放引用计数
    6     CloseHandle(hThread);
    7 
    8     return TRUE;
    9 }
    复制代码

    线程处理函数:

    复制代码
     1 DWORD WINAPI TcpServer::ThreadProc_Accept(LPVOID lpParameter)
     2 {
     3     int len = sizeof(SOCKADDR);
     4     int err;
     5     m_socket=socket(AF_INET,SOCK_STREAM,0);
     6     if (m_socket == INVALID_SOCKET)
     7     {
     8         AfxMessageBox(_T("套接字创建失败!"));
     9         return FALSE;
    10     }
    11 
    12     SOCKADDR_IN addrSrv;
    13     addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
    14     addrSrv.sin_family=AF_INET;
    15     addrSrv.sin_port=htons(8099);
    16 
    17     err = bind(m_socket,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));    //绑定本地端口
    18     if (err==SOCKET_ERROR)
    19     {
    20         closesocket(m_socket);
    21         AfxMessageBox(_T("绑定失败!"));
    22         return FALSE;
    23     }
    24     listen(m_socket,10);//开启监听
    25 
    26     //创建线程
    27     HANDLE hThread = CreateThread(NULL,0,ThreadProc_Select,NULL,0,NULL);
    28     //关闭该接收线程句柄,释放引用计数
    29     CloseHandle(hThread);
    30 
    31     while (TRUE)
    32     {
    33         m_CliSocketArr[m_ToolConn++] = accept(m_socket,(SOCKADDR*)&addrSrv,&len);
    34     }
    35     return 0;
    36 }
    复制代码

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

    复制代码
     1 DWORD WINAPI TcpServer::ThreadProc_Select(LPVOID lpParameter)
     2 {
     3     int recvflag=0;
     4 
     5     fd_set    fdread;                //读集fdread
     6     int        ret;                //查看某个套接字的状态
     7     struct timeval tv = {1,0};    //实例化timeval变量
     8 
     9     while (TRUE)
    10     {
    11         //判断当前连接数是否为 0
    12         if (m_ToolConn == 0)
    13         {
    14             Sleep(50);
    15             continue;
    16         }
    17 
    18         FD_ZERO(&fdread);
    19         for (int i = 0;i < m_ToolConn;i++)
    20         {
    21             FD_SET(m_CliSocketArr[i],&fdread);
    22         }
    23         ret = select(0,&fdread,NULL,NULL,&tv);
    24         if (ret == 0)
    25         {
    26             continue;
    27         }
    28         for (int i =0;i<m_ToolConn;i++)
    29         {
    30             if (FD_ISSET(m_CliSocketArr[i],&fdread))
    31             {
    32                 ret = recv(m_CliSocketArr[i],(char*)&recvflag,sizeof(int)+1,0);
    33                 if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
    34                 {
    35                     closesocket(m_CliSocketArr[i]);
    36                     if (i < m_ToolConn-1)
    37                     {
    38                         m_CliSocketArr[i] = m_CliSocketArr[--m_ToolConn];
    39                     }else
    40                     {
    41                         --m_ToolConn;
    42                     }
    43 
    44                 }else
    45                 {
    46                     INDEX * inx = new INDEX;
    47                     inx->flag  = recvflag;
    48                     inx->index = i;
    49 
    50                     //创建线程
    51                     HANDLE hThread = CreateThread(NULL,0,ThreadProc_Response,(LPVOID)inx,0,NULL);
    52                     //关闭该接收线程句柄,释放引用计数
    53                     CloseHandle(hThread);
    54 
    55                 }
    56             }//if
    57         }//for
    58     }//while
    59 
    60     return 0;
    61 }
    复制代码

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

    复制代码
     1 DWORD WINAPI TcpServer::ThreadProc_Response(LPVOID lpParameter)
     2 {
     3     int ix = ((INDEX*)lpParameter)->index;
     4     int flag = ((INDEX*)lpParameter)->flag;
     5 
     6     delete lpParameter;
     7 
     8     if (flag == 1)
     9     {
    10         //.............................
    11         unsigned char sendBuffer[1024] = {'a'};
    12         send(m_CliSocketArr[ix],(char*)sendBuffer,sizeof(sendBuffer)+1,0);
    13     }
    14 
    15     return 0;
    16 }
    复制代码

    这里线程的创建以及处理也可以使用_beginthread()去实现。

    另外里面没有做太多的资源释放等等,如果真正去用的话,是应该注意的。

  • 相关阅读:
    反射技术的入口 获取类的Class信息
    Dom4j(Dom for Java) Day24
    通过反射 修改访问和修改属性的值 Day25
    通过反射 往泛型Integer的集合里添加String 类型的数据 Day25
    计算机网络(七),TCP与UDP的区别
    计算机网络(六),UDP报文段详解
    计算机网络(五),TCP四次挥手
    计算机网络(四),TCP三次握手
    计算机网络(三),TCP报文段详解
    计算机网络(二),TCP/IP四层模型常见协议
  • 原文地址:https://www.cnblogs.com/IamQtCreator/p/4608340.html
Copyright © 2011-2022 走看看