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()去实现。
另外里面没有做太多的资源释放等等,如果真正去用的话,是应该注意的。

浙公网安备 33010602011771号