下面的程序,使用了多线程。端口连接方面,使用的是异步套接字(ioctlsocket),使用I/O复用Select实现异步端口查询,加快程序速度。

但是超时时间不好定,优化的还有很多。

   
   
   
   
  1. #include   
  2. #include   
  3. #include   
  4. #pragma comment(lib, "ws2_32.lib")  
  5.  
  6. char    *host;  
  7. int     nThreadNum, nMaxThread, nTotalPort;  
  8. long    lNowPort;  
  9. // select  
  10. TIMEVAL timeout;  
  11. FD_SET  mask;  
  12. void Usage()  
  13. {  
  14.     printf("\tusage: %s IP StartPort-EndPort Maxthread(1000)\n");  
  15.     printf("\tExample:192.168.0.1 1-10000 500\n");  
  16. }  
  17.  
  18. // 状态提示函数  
  19. void Display()  
  20. {  
  21.     static int play = 0;  
  22.     char *playsProgress[12] = {  
  23.         " | ",  
  24.         " / ",  
  25.         " - ",  
  26.         " \\ ",  
  27.         " | ",  
  28.         " / ",  
  29.         " - ",  
  30.         " \\ ",  
  31.         " | ",  
  32.         " / ",  
  33.         " - ",  
  34.         " \\ " 
  35.     };  
  36.     // 显示进度条和线程数  
  37.     printf(" = %s = \t %d threads   %d%s Completed. \r",  
  38.             playsProgress[play], nThreadNum, (lNowPort*100) /(nTotalPort+1), "%");  
  39.     play = (play == 11)?0:play + 1;  
  40.     Sleep(1);  
  41. }  
  42.  
  43. void WaitThreadEnd()  
  44. {  
  45.     Sleep(1000);  
  46.     printf("\n Thread Ending...\n");  
  47.     while(nThreadNum > 0)  
  48.     {  
  49.         Sleep(1);  
  50.         printf("=|=\t%d threads \r", nThreadNum);  
  51.     }  
  52.     printf("\n Thread ended!\n");  
  53. }  
  54.  
  55. DWORD WINAPI ThreadFunc(LPVOID lp)  
  56. {  
  57.     int port = *(DWORD*)lp;  
  58.     SOCKET  socketUse;  
  59.     struct  sockaddr_in addr;  
  60.  
  61.     u_long  value;  
  62.     addr.sin_family = AF_INET;  
  63.     addr.sin_addr.s_addr = inet_addr(host);  
  64.     value = 1;  
  65.     socketUse = socket(AF_INET, SOCK_STREAM, 0);  
  66.     if(socketUse == INVALID_SOCKET)  
  67.     {  
  68.         printf("Socket error!\n");  
  69.         // 线程数减一  
  70.         InterlockedExchangeAdd((long*)&nThreadNum, -1); //  
  71.         return 0;  
  72.     }  
  73.     // 把socket设定为非阻塞模式  
  74.     ioctlsocket(socketUse, FIONBIO, &value);  
  75.     addr.sin_port = htons(port);  
  76.     // 连接测试  
  77.     connect(socketUse, (struct sockaddr*)&addr, sizeof(addr));  
  78.     // I/O复用  
  79.     FD_ZERO(&mask);  
  80.     FD_SET(socketUse, &mask);  
  81.     value = select(0, NULL, &mask, NULL, &timeout);  
  82.     if(value == 0 || value == -1)  
  83.     {  
  84.         closesocket(socketUse);  
  85.         Sleep(50);  
  86.         InterlockedExchangeAdd((long*)&nThreadNum, -1); //  
  87.         return 0;  
  88.     }  
  89.     else 
  90.     {  
  91.         // 阻止socket接收和发送数据  
  92.         shutdown(socketUse, 0);       
  93.         printf("\tFound port %d open.\r\n", port);  
  94.         closesocket(socketUse);  
  95.         Sleep(50);  
  96.         InterlockedExchangeAdd((long*)&nThreadNum, -1);  
  97.     }  
  98.     return 0;  
  99. }  
  100.  
  101. int main(int argc, char **argv)  
  102. {  
  103.     WSADATA     ws;  
  104.     char*       pPorts;  
  105.     int         nStartPort, nEndPort;  
  106.     clock_t     start, end;  
  107.     float       costTime;  
  108.     if(argc != 4)  
  109.     {  
  110.         Usage();  
  111.         return 0;  
  112.     }  
  113.     long lResult;  
  114.     lResult = WSAStartup(MAKEWORD(2, 2), &ws);  
  115.     pPorts = argv[2];  
  116.     if(strstr(argv[2], "-"))  
  117.     {  
  118.         nStartPort = atoi(argv[2]);  
  119.         for(; *pPorts; )  
  120.         {  
  121.             if(*(pPorts++) == '-')  
  122.                 break;  
  123.         }  
  124.         nEndPort = atoi(pPorts);  
  125.         if(nStartPort<1 || nEndPort > 65535)  
  126.         {  
  127.             printf("Port Error!\n");  
  128.             return 0;  
  129.         }  
  130.     }  
  131.     host = argv[1];  
  132.     nMaxThread = (atoi(argv[3])-1 > 999)? 999 : atoi(argv[3])-1;  
  133.     //Usage();  
  134.     // 设置连接超时, 如果线程数大于500, 则超时为两秒  
  135.     timeout.tv_usec = 3;  
  136.     if(nMaxThread > 500)  
  137.         timeout.tv_usec = 4;  
  138.     // begin  
  139.     start = clock();  
  140.     nTotalPort = nEndPort - nStartPort;  
  141.     for(int nPort = nStartPort; nPort < nEndPort; nPort++, lNowPort++, nThreadNum++)  
  142.     {  
  143.         Display();   
  144.         while(nThreadNum > nMaxThread)  
  145.             Sleep(10);  
  146.         // 线程  
  147.         CreateThread(NULL, 0, ThreadFunc, &nPort, 0, NULL);  
  148.     }  
  149.     end = clock();  
  150.     costTime = (float)(end - start);  
  151.     printf("\nCost time: %f Sec\n", costTime);  
  152.     printf("\n\n");  
  153.     WaitThreadEnd();  
  154.     WSACleanup();  
  155.     system("pause");  
  156.     return 0;  

 

参考:<>