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()去实现。

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

posted on 2015-06-29 19:36  areu-me  阅读(281)  评论(0编辑  收藏  举报

导航