搜索
查看: 673|回复: 2

[C++]初学多线程写的端口扫描

[复制链接]

1839

主题

2255

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
11913
发表于 2013-12-4 17:04:14 来自手机 | 显示全部楼层 |阅读模式

  1. // PortScan.cpp
  2. //
  3. //=============================================================================
  4. // PortScan - 端口扫描程序
  5. //
  6. // XXXXXXXXXXXXXXX
  7. //
  8. // XXXXXXXXXXXXXXX
  9. //=============================================================================
  10. #include <winsock2.h>
  11. #include <stdio.h>
  12. #pragma comment(lib,"ws2_32.lib")

  13. DWORD WINAPI ScanThread(LPVOID lp);

  14. //保存扫描的主机IP和端口的结构
  15. typedef struct{
  16.         char HostIp[17];
  17.         int ScanPort;
  18. }HostStruct;

  19. long lPortOpen = 0; // 统计开放端口数

  20. //帮助
  21. void Help(char *argv0)
  22. {
  23.         printf("\nPortScan.exe");
  24.         printf("\nUsage:");
  25.         printf("\n\t%s 127.0.0.1 1 3389\n",argv0);
  26.         exit(0);
  27. }

  28. //==============================================================================
  29. // 线程函数
  30. //==============================================================================
  31. DWORD WINAPI ScanThread(LPVOID lp)
  32. {
  33.         struct sockaddr_in sin;                // sockaddr_in结构
  34.         HostStruct *lpScanHost=(HostStruct*)lp;  // 将参数传化成HostStruct结构指针
  35.         SOCKET s = socket(AF_INET,SOCK_STREAM,0);

  36.         // 给结构成员赋值
  37.         sin.sin_family = AF_INET;
  38.         sin.sin_port = htons(lpScanHost->ScanPort);
  39.         sin.sin_addr.S_un.S_addr = inet_addr(lpScanHost->HostIp);

  40.         // 建立连接
  41.         if(connect(s,(struct sockaddr*)&sin,sizeof(sin)) != SOCKET_ERROR)
  42.         {
  43.             printf("\n%s:%d\tOPEN",lpScanHost->HostIp,lpScanHost->ScanPort);
  44.             InterlockedIncrement(&lPortOpen);                // 原子性++         相对        InterlockedDecrement 原子性--
  45.         }
  46.         closesocket(s);        // 无论连接是否成功都需要关闭socket
  47.         return 0;
  48. }

  49. int main(int argc, char* argv[])
  50. {
  51.         WORD wVersion = MAKEWORD(2,0); //socket的版本
  52.         WSADATA wsaData;
  53.         int iFromPort;        //开始端口
  54.         int iToPort;          //结束端口
  55.         int iNowPort;          //正在扫描的端口
  56.         int iPortCount;        //端口总数
  57.         int badCount=0;        //线程失败数,有时候失败是因为目标设置了最大连接数

  58.         //如果命令行下参数不是4个,提示正确的用法
  59.         if(argc != 4)
  60.             Help(argv[0]);

  61.         //保存用户输入的要扫描的起始端口和结束端口,由于用户输入的是char型,所以要先转成int型  
  62.         iFromPort = atoi(argv[2]);
  63.         iToPort = atoi(argv[3]);

  64.         //对用户输入的端口进行判断
  65.         if(iFromPort > iToPort || iToPort >65535 || iFromPort < 0)
  66.             return -1;

  67.         if (WSAStartup(wVersion , &wsaData))
  68.             return -1;

  69.         //要扫描的端口总数
  70.         iPortCount = iToPort - iFromPort + 1;

  71.         // 根据端口数创建线程句柄数
  72.         HANDLE *hThreads = new HANDLE[iPortCount];
  73.         ZeroMemory(hThreads,sizeof(HANDLE)*iPortCount);
  74.         //
  75.         // 根据端口数创建线程参数结构指针,使用它只是为了记录结构指针,用于主线程释放动态内存
  76.         //
  77.         HostStruct** pScanHosts = new HostStruct*[iPortCount];
  78.         ZeroMemory(pScanHosts,sizeof(HostStruct*)*iPortCount);

  79.         printf("\n====== Scanning ======\n");

  80.         //循环连接端口,以判断端口是否开放
  81.         int iThreadCount = 0; // 成功创建的线程数目计数
  82.         int iParamCount = 0;  // 线程句柄数组索引
  83.         for(iParamCount = 0, iNowPort = iFromPort; iNowPort <= iToPort; iParamCount++,iNowPort++)
  84.         {
  85.             // 为单独的线程提供单独的线程参数,此参数不能在局部栈上分配
  86.             pScanHosts[iParamCount] = new HostStruct;
  87.             strcpy( pScanHosts[iParamCount]->HostIp,argv[1]);
  88.             pScanHosts[iParamCount]->ScanPort = iNowPort;
  89.             HANDLE hThread = CreateThread(NULL,NULL,ScanThread,pScanHosts[iParamCount],NULL,NULL);
  90.             if(hThread != NULL){
  91.             hThreads[iThreadCount++] = hThread;//只统计正常运行的线程
  92.             if(iThreadCount%64==0) Sleep(200);                // 每成功创建64个线程,停顿200毫秒(多次测试后的合理取值),降低CPU
  93.             }
  94.             else
  95.             badCount++;
  96.         }

  97.         // 等待线程执行完毕,这一步是必须的,否则上面分配的动态内存会过早释放,线程执行时参数数据将出现异常
  98.         // WaitForMultipleObjects 所能等待的对象最大不能超过MAXIMUM_WAIT_OBJECTS (64)个,如果超过,进行分组等待
  99.         //
  100.         for(int iGroup = 0; iThreadCount>0; iGroup ++, iThreadCount -= MAXIMUM_WAIT_OBJECTS)
  101.         {
  102.             WaitForMultipleObjects(
  103.             iThreadCount>MAXIMUM_WAIT_OBJECTS ? MAXIMUM_WAIT_OBJECTS : iThreadCount,
  104.             hThreads+iGroup*MAXIMUM_WAIT_OBJECTS,
  105.             TRUE,
  106.             256);              // 此参数单位为毫秒,若为INFINITE则代表一直等待,直到线程返回
  107.         }

  108.         printf("\n\n======  OK     ======");
  109.         printf("\n\tBad threads %d : %d",iPortCount,badCount);
  110.         printf("\n\tDetected open ports %ld\n",lPortOpen);

  111.         // 释放所有动态分配的内存
  112.         delete[iPortCount] hThreads;
  113.         for(int ii=0; ii < iPortCount; ii ++ )
  114.             delete pScanHosts[ii];
  115.         delete[iPortCount] pScanHosts;
  116.         WSACleanup();
  117.         return 0;
  118. }
复制代码
854955425 该用户已被删除
发表于 2013-12-4 17:06:09 | 显示全部楼层
真是 收益 匪浅
专业回帖 该用户已被删除
发表于 2013-12-4 18:00:53 | 显示全部楼层
学习了,谢谢分享、、、
您需要登录后才可以回帖 登录 | Join BUC

本版积分规则

Powered by Discuz!

© 2012-2015 Baiker Union of China.

快速回复 返回顶部 返回列表