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()去實現。

另外里面沒有做太多的資源釋放等等,如果真正去用的話,是應該注意的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM