Windows socket I/O模型 之 select(2)

在Windows socket I/O模型 之 select(1)中,我们只是在console中简单的模拟了select的处理方法。


还有很多特性不能修改,比如只能写,不能读。

没使用线程,也没有同步不同的读写线程。


先谈谈个人目前对select的理解。

select就是监控一组套接字的变化情况。

比如一个fd_set的变量(暂且定义为fdRead)里面有5个套接字,当你传给select后,假设只有2个被触发。

那么这个fdRead也就改变了。这是为什么select需要从全局fd_set拷贝一份给select的原因。


然后我们根据套接字的变化情况做相应的处理就OK了,但是大并发量还没有测试。


今晚我改进了。下面大家见代码。。。。。。

[cpp] view plain copy print ?
  1. // Select_Server.cpp : Defines the entry point for the console application.  
  2. // 服务端  
  3.   
  4. #include "stdafx.h"  
  5.   
  6.   
  7. #define STR_SERVER_IP           "127.0.0.1"  
  8. #define INT_SERVER_PORT         8001  
  9. #define INT_DATABUFFER_SIZE     256  
  10.   
  11.   
  12. SOCKET g_soClient;  
  13. typedef std::list<SOCKET>   LstSocket;  
  14. LstSocket                   g_lstSoClient;  
  15.   
  16. SOCKET g_soServer;  
  17. fd_set g_fdSocketSet;  
  18.   
  19. // for thread synchronize  
  20. CCriSec     g_criSec;  
  21.   
  22. DWORD WINAPI ThreadRead(LPVOID lpvParam)  
  23. {  
  24.     int iResult = 0;  
  25.     sockaddr_in addrAccept;  
  26.     int iAcceptLen = sizeof(addrAccept);  
  27.     SOCKET soClient;  
  28.   
  29.     FD_ZERO(&g_fdSocketSet);  
  30.     FD_SET(g_soServer, &g_fdSocketSet);  
  31.     fd_set fdRead, fdWrite;  
  32.     while( TRUE ) {  
  33.         // initialize  
  34.         FD_ZERO(&fdRead);  
  35.         FD_ZERO(&fdWrite);  
  36.         fdRead = g_fdSocketSet;  
  37.         fdWrite = g_fdSocketSet;  
  38.   
  39.         int n1 = fdRead.fd_count;  
  40.         int n2 = fdWrite.fd_count;  
  41.         int n3 = g_fdSocketSet.fd_count;  
  42.         int iResult = select(0, &fdRead, &fdWrite, NULL, NULL);  
  43.         if( iResult == SOCKET_ERROR) {  
  44.             break;  
  45.         }  
  46.   
  47.         if(FD_ISSET(g_soServer, &fdRead)) {  
  48.             soClient = accept(g_soServer, (sockaddr*)&addrAccept, &iAcceptLen);  
  49.   
  50.             CCriSecLock lock(g_criSec);  
  51.             if(soClient == INVALID_SOCKET) {  
  52.                 continue;  
  53.             } else {  
  54.                 printf("\n[%s:%d] has connected to server!\r\n", inet_ntoa(addrAccept.sin_addr),  
  55.                     ntohs(addrAccept.sin_port));  
  56.                 FD_SET(soClient, &g_fdSocketSet);  
  57.             }  
  58.         } else {  
  59.             // check read  
  60.             for(int i=0; i < (int)fdRead.fd_count; i++) {  
  61.                 if ( fdRead.fd_array[i] == g_soServer ) {  
  62.                     continue;  
  63.                 }  
  64.   
  65.                 if( FD_ISSET(fdRead.fd_array[i], &g_fdSocketSet) ) {  
  66.                     sockaddr_in name;  
  67.                     int namelen = sizeof(sockaddr_in);  
  68.                     getpeername(fdRead.fd_array[i], (sockaddr *)&name, &namelen);  
  69.   
  70.                     char buf[256] = {0};  
  71.                     int len = 256;  
  72.                     int ret = recv(fdRead.fd_array[i], buf, len, 0);  
  73.                     CCriSecLock lock(g_criSec);  
  74.                     if( ret == SOCKET_ERROR ) {  
  75.                         int nErr = GetLastError();  
  76.                         if( nErr == 10054 ) {  
  77.                             // Connection reset by peer.  
  78.                             FD_CLR(fdRead.fd_array[i], &g_fdSocketSet);  
  79.                             printf("\n[%s:%d] disconnect from server.\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port) );  
  80.                         } else {  
  81.                             printf("\nfdread failed with %d\n", nErr);  
  82.                         }  
  83.                     } else {  
  84.                         printf("\nRecv from [%s:%d] : %s\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port), buf);  
  85.                     }  
  86.                 }  
  87.             }  
  88.               
  89.             // check write  
  90.             static bool b11 = false;  
  91.             for(int i=0; i < (int)fdWrite.fd_count; i++) {  
  92.                 if( FD_ISSET(fdWrite.fd_array[i], &g_fdSocketSet) ) {  
  93.                     char buf[256] = "abcd";  
  94.                     int len = 256;  
  95.                     if( !b11 ) {  
  96.                         b11 = true;  
  97.                         //send(fdWrite.fd_array[i], buf, len ,0);  
  98.                     }  
  99.                 }  
  100.             }  
  101.         }  
  102.     }  
  103.   
  104.     return 0;  
  105. }  
  106.   
  107. DWORD WINAPI ThreadWrite(LPVOID lpvParam)  
  108. {  
  109.     std::string str;  
  110.     {  
  111.         CCriSecLock lock(g_criSec);  
  112.         std::cout << "Please input message to client: ";  
  113.     }  
  114.     while( getline(std::cin, str) ) {  
  115.         if( str.compare("exit") == 0 ) {  
  116.             {  
  117.                 CCriSecLock lock(g_criSec);  
  118.                 printf("close write thread\n");  
  119.             }  
  120.             break;  
  121.         }  
  122.   
  123.         for(int i = 1; i < (int)g_fdSocketSet.fd_count; i++) {  
  124.             send(g_fdSocketSet.fd_array[i], str.data(), (int)str.size(), 0);  
  125.         }  
  126.     }  
  127.       
  128.     return 0;  
  129. }  
  130.   
  131. int _tmain(int argc, _TCHAR* argv[])  
  132. {  
  133.     WORD dwVersion = MAKEWORD(2, 2);  
  134.     WSAData wsaData;  
  135.     WSAStartup(WINSOCK_VERSION,&wsaData);  
  136.   
  137.     g_soServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  138.     if (INVALID_SOCKET == g_soServer) {  
  139.         printf("Failed to create socket!\r\n");  
  140.         WSACleanup();  
  141.         return -1;  
  142.     }  
  143.   
  144.     sockaddr_in addrServer;  
  145.     memset(&addrServer,0,sizeof(sockaddr_in));  
  146.     addrServer.sin_family = AF_INET;  
  147.     addrServer.sin_port = htons(INT_SERVER_PORT);  
  148.     addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);  
  149.   
  150.     int iResult;  
  151.   
  152.     bool bReuseAddr = true;  
  153.     iResult = setsockopt(g_soServer, SOL_SOCKET, SO_REUSEADDR, (char *)&bReuseAddr, sizeof(bReuseAddr));  
  154.     if(SOCKET_ERROR == iResult) {  
  155.         printf("Failed to set resueaddr socket!\r\n");  
  156.         WSACleanup();  
  157.         return -1;  
  158.     }  
  159.   
  160.     //设置非阻塞方式连接  
  161.     unsigned long cmd = 1;  
  162.     iResult = ioctlsocket(g_soServer, FIONBIO, &cmd);  
  163.   
  164.     iResult = bind(g_soServer, (sockaddr *)&addrServer, sizeof(addrServer));  
  165.     if (SOCKET_ERROR == iResult) {  
  166.         printf("Failed to bind address!\r\n");  
  167.         WSACleanup();  
  168.         return -1;  
  169.     }  
  170.   
  171.     if (0 != listen(g_soServer, 5)) {  
  172.         printf("Failed to listen client!\r\n");  
  173.         WSACleanup();  
  174.         return -1;  
  175.     }  
  176.   
  177.     printf("Start server...\r\n");  
  178.   
  179.     HANDLE hWorkRead = CreateThread(NULL, 0, ThreadRead, NULL, 0, NULL);  
  180.     HANDLE hWorkWrite = CreateThread(NULL, 0, ThreadWrite, NULL, 0, NULL);  
  181.   
  182.     ::WaitForSingleObject(hWorkRead, INFINITE);  
  183.     ::WaitForSingleObject(hWorkWrite, INFINITE);  
  184.   
  185.     WSACleanup();  
  186.   
  187.     return 0;  
  188. }  

下面是客户端代码:
[cpp] view plain copy print ?
  1. // Select_Client.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6.   
  7.   
  8. #define INT_SERVER_PORT 8001  
  9. #define STR_SERVER_IP "127.0.0.1"  
  10. #define INT_DATABUFFER_SIZE 256  
  11. #define STR_EXIT "exit"  
  12. #define STR_RECV "recv"  
  13.   
  14. //  
  15. SOCKET g_soClient;  
  16. fd_set g_fdSocketSet;  
  17.   
  18. // for thread synchronize  
  19. CCriSec     g_criSec;  
  20.   
  21. DWORD WINAPI ThreadWorker(LPVOID lpvParam)  
  22. {  
  23.     FD_ZERO(&g_fdSocketSet);  
  24.     FD_SET(g_soClient, &g_fdSocketSet);  
  25.     fd_set fdRead, fdWrite;  
  26.       
  27.     while( TRUE ) {  
  28.         // initialize  
  29.         FD_ZERO(&fdRead);  
  30.         FD_ZERO(&fdWrite);  
  31.         fdRead = g_fdSocketSet;  
  32.         fdWrite = g_fdSocketSet;  
  33.           
  34.         int iResult = select(0, &fdRead, &fdWrite, NULL, NULL);  
  35.         if( iResult == SOCKET_ERROR) {  
  36.             break;  
  37.         } else if( iResult == 0 ) {  
  38.             printf("Time limit expired\n");  
  39.         } else {  
  40.             // check read  
  41.             if (FD_ISSET(fdRead.fd_array[0], &g_fdSocketSet)) {  
  42.                 sockaddr_in name;  
  43.                 int namelen = sizeof(sockaddr_in);  
  44.                 getpeername(fdRead.fd_array[0], (sockaddr *)&name, &namelen);  
  45.   
  46.                 char buf[256] = {0};  
  47.                 int len = 256;  
  48.                 int ret = recv(fdRead.fd_array[0], buf, len, 0);  
  49.                 CCriSecLock lock(g_criSec);  
  50.                 if( ret == SOCKET_ERROR ) {  
  51.                     int nErr = GetLastError();  
  52.                     if( nErr == 10054 ) {  
  53.                         // Connection reset by peer.  
  54.                         FD_CLR(fdRead.fd_array[0], &g_fdSocketSet);  
  55.                         printf( "\n[%s:%d] is closed.\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port) );  
  56.                     } else {  
  57.                         printf("fdread failed with %d\n", nErr);  
  58.                     }  
  59.                 } else {  
  60.                     CCriSecLock lock(g_criSec);  
  61.                     printf("\nRecv from [%s:%d] : %s\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port), buf);  
  62.                 }  
  63.             }  
  64.   
  65.             // check write  
  66.             if (FD_ISSET(fdWrite.fd_array[0], &g_fdSocketSet)) {  
  67.                 int a=2;  
  68.                 int b=a;  
  69.             }  
  70.         }  
  71.     }  
  72.       
  73.     return 0;  
  74. }  
  75.   
  76. void main(void)  
  77. {  
  78.     WSAData wsaData;  
  79.     WSAStartup(WINSOCK_VERSION,&wsaData);  
  80.     
  81.     g_soClient = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);  
  82.     if (INVALID_SOCKET == g_soClient) {  
  83.         printf("Failed to create client!\r\n");  
  84.         WSACleanup();  
  85.     }  
  86.     
  87.     sockaddr_in addrServer;  
  88.     addrServer.sin_addr.S_un.S_addr = inet_addr(STR_SERVER_IP);  
  89.     addrServer.sin_family = AF_INET;  
  90.     addrServer.sin_port = htons(INT_SERVER_PORT);  
  91.   
  92.     int iResult;  
  93.   
  94.     //设置非阻塞方式连接  
  95.     //unsigned long ul = 1;  
  96.     //iResult = ioctlsocket(g_soClient, FIONBIO, (unsigned long*)&ul);  
  97.       
  98.     iResult = connect(g_soClient, (sockaddr *)&addrServer, sizeof(sockaddr_in));  
  99.     if (SOCKET_ERROR == iResult) {  
  100.         printf("Failed to connect server!(Error: %d)\r\n", ::WSAGetLastError());  
  101.         WSACleanup();  
  102.         return;  
  103.     }  
  104.       
  105.     HANDLE hWorker = CreateThread(NULL, 0, ThreadWorker, NULL, 0, NULL);  
  106.   
  107.     std::string str;  
  108.     std::cout << "Please input message to server: ";  
  109.     while( getline(std::cin, str) ) {  
  110.         send(g_soClient, str.data(), str.size(), 0);  
  111.         std::cout << "Please input message to client: ";  
  112.     }  
  113.   
  114.     closesocket(g_soClient);  
  115.     WSACleanup();  
  116. }  

头文件
[cpp] view plain copy print ?
  1. // stdafx.h : include file for standard system include files,  
  2. // or project specific include files that are used frequently, but  
  3. // are changed infrequently  
  4. //  
  5.   
  6. #pragma once  
  7.   
  8. #ifndef _WIN32_WINNT        // Allow use of features specific to Windows XP or later.                     
  9. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.  
  10. #endif                        
  11.   
  12. #include <stdio.h>  
  13. #include <tchar.h>  
  14. #include <string>  
  15. #include <iostream>  
  16. #include <WINSOCK2.H>  
  17.   
  18. #pragma comment(lib,"ws2_32.lib")  
  19.   
  20.   
  21.   
  22. // TODO: reference additional headers your program requires here  
  23. #include "CriticalSection.h"  

// CriticalSection.h
[cpp] view plain copy print ?
  1. /* 
  2.  * Copyright: JessMA Open Source ([email protected]) 
  3.  * 
  4.  * Version  : 2.3.2 
  5.  * Author   : Bruce Liang 
  6.  * Website  : http://www.jessma.org 
  7.  * Project  : https://github.com/ldcsaa 
  8.  * Blog     : http://www.cnblogs.com/ldcsaa 
  9.  * Wiki     : http://www.oschina.net/p/hp-socket 
  10.  * QQ Group : 75375912 
  11.  * 
  12.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  13.  * you may not use this file except in compliance with the License. 
  14.  * You may obtain a copy of the License at 
  15.  * 
  16.  *      http://www.apache.org/licenses/LICENSE-2.0 
  17.  * 
  18.  * Unless required by applicable law or agreed to in writing, software 
  19.  * distributed under the License is distributed on an "AS IS" BASIS, 
  20.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  21.  * See the License for the specific language governing permissions and 
  22.  * limitations under the License. 
  23.  */  
  24.    
  25. /**************************************************************************** 
  26. *                                                                           * 
  27. * CriticalSection.h                                                         * 
  28. *                                                                           * 
  29. * Create by :                                                               * 
  30. * Kingfisher    2003-10-15                                                  * 
  31. *                                                                           * 
  32. * Description:                                                              * 
  33. * 封装Win32临界量对象和互斥量内核对象                                          * 
  34. ****************************************************************************/  
  35.   
  36. #pragma once  
  37.   
  38. #include <windows.h>  
  39.   
  40. class CCriSec  
  41. {  
  42. public:  
  43.     CCriSec()       {::InitializeCriticalSection(&m_crisec);}  
  44.     ~CCriSec()      {::DeleteCriticalSection(&m_crisec);}  
  45.   
  46.     void Lock()     {::EnterCriticalSection(&m_crisec);}  
  47.     void Unlock()   {::LeaveCriticalSection(&m_crisec);}  
  48.   
  49. private:  
  50.     CCriSec(const CCriSec& cs);  
  51.     CCriSec operator = (const CCriSec& cs);  
  52.   
  53. private:  
  54.     CRITICAL_SECTION    m_crisec;  
  55. };  
  56.   
  57. class CCriSec2  
  58. {  
  59. public:  
  60.     CCriSec2(BOOL bInitialize = TRUE)  
  61.     {  
  62.         if(bInitialize)  
  63.         {  
  64.             m_pcrisec = new CRITICAL_SECTION;  
  65.             ::InitializeCriticalSection(m_pcrisec);  
  66.         }  
  67.         else  
  68.             m_pcrisec = NULL;  
  69.     }  
  70.   
  71.     ~CCriSec2() {Reset();}  
  72.   
  73.     void Attach(CRITICAL_SECTION* pcrisec)  
  74.     {  
  75.         Reset();  
  76.         m_pcrisec = pcrisec;  
  77.     }  
  78.   
  79.     CRITICAL_SECTION* Detach()  
  80.     {  
  81.         CRITICAL_SECTION* pcrisec = m_pcrisec;  
  82.         m_pcrisec = NULL;  
  83.         return pcrisec;  
  84.     }  
  85.   
  86.     void Lock()     {::EnterCriticalSection(m_pcrisec);}  
  87.     void Unlock()   {::LeaveCriticalSection(m_pcrisec);}  
  88.   
  89. private:  
  90.     CCriSec2(const CCriSec2& cs);  
  91.     CCriSec2 operator = (const CCriSec2& cs);  
  92.   
  93.     void Reset()  
  94.     {  
  95.         if(m_pcrisec)  
  96.         {  
  97.             ::DeleteCriticalSection(m_pcrisec);  
  98.             delete m_pcrisec;  
  99.             m_pcrisec = NULL;  
  100.         }  
  101.     }  
  102.   
  103. private:  
  104.     CRITICAL_SECTION*    m_pcrisec;  
  105. };  
  106.   
  107.   
  108. template<class CLockObj> class CLocalLock  
  109. {  
  110. public:  
  111.     CLocalLock(CLockObj& obj) : m_lock(obj) {m_lock.Lock();}  
  112.     ~CLocalLock() {m_lock.Unlock();}  
  113. private:  
  114.     CLockObj& m_lock;  
  115. };  
  116.   
  117. typedef CLocalLock<CCriSec>       CCriSecLock;  
  118. typedef CLocalLock<CCriSec2>  CCriSecLock2; 

你可能感兴趣的:(Windows socket I/O模型 之 select(2))