求c++ 高手看看一段代码 为什么使用多线程 扫描速度还是很慢

时间:2020-12-01 08:53:18
#include <Windows.h>
#include <iostream>
#include <winsock.h>
#pragma comment(lib,"wsock32.lib")
#define DEF_BUF_SIZE 1024
#define ICMP_HEADER_SIZE 12
typedef struct _ICMP_HEADER 
{
    BYTE bType;    
    USHORT nCheckSum; 
}ICMP_HEADER, *PICMP_HEADER;


USHORT GetCheckSum(LPBYTE lpBuff, DWORD dwSize)
{
    DWORD dwCheckSum = 0;
    USHORT* lpWord = (USHORT*)lpBuff;
    while(dwSize > 1)
    {
        dwCheckSum += *lpWord++;
        dwSize -= 2;
    }
    if(dwSize ==1)
    dwCheckSum += *((LPBYTE)lpBuff);
    return (USHORT)(~dwCheckSum);
}


DWORD WINAPI Thread(LPVOID lpParmeter);
HANDLE g_hMutex;


int main()
{  
   static int u=2,i=0; 
   HANDLE* hThread = new HANDLE[u];  
   WSADATA wsaData; 
   WORD wVersionRequested;
   wVersionRequested = MAKEWORD( 1, 1 ); 
   WSAStartup( wVersionRequested, &wsaData ); 

   for(;i<u; i++)
{
  g_hMutex=CreateMutex(NULL,FALSE,"MutexToRecive");
  hThread[i]=CreateThread(NULL,0,Thread,&i,0,NULL);
  Sleep(50);
}

 SetEvent(g_hMutex); 
 WaitForMultipleObjects(i, hThread, TRUE, INFINITE);
 for (; i<u; i++)
 CloseHandle(hThread[i]);
 return 0;
}


DWORD WINAPI Thread(LPVOID lpParmeter)
{   int x=3389,nRet;
int idx = *(int*)lpParmeter;
    SOCKET s = socket(AF_INET,SOCK_RAW, IPPROTO_ICMP);

    if(s == INVALID_SOCKET)
{
        printf("SOCKET error Code for the %s\n",s);
        return 0;
}

    struct sockaddr_in addr; 
    addr.sin_family =AF_INET;
    addr.sin_port = htons(x);
    static  unsigned   long iSIP   =   inet_addr("192.168.1.1");
    static  unsigned   long iEIP   =   inet_addr("192.168.1.26");
    static  unsigned long s1 = ntohl(iSIP);
    static  unsigned long e1 = ntohl(iEIP);
for(;s1 <= e1;s1++) 

        WaitForSingleObject(g_hMutex, INFINITE);
if (s1 <= e1)
{   

Sleep(3);
addr.sin_addr.S_un.S_addr    =   ntohl(s1);//获取每次For循环后的IP
    char ICMPPack[ICMP_HEADER_SIZE] = {0};
    PICMP_HEADER pICMPHeader = (PICMP_HEADER)ICMPPack;
    pICMPHeader->bType = 8;//定义8位字节的数据包
    int nTime = 1000; //设置超时时间
    int ret = ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTime, sizeof(nTime));//发送的数据包到目标IP,超时就结束发送
    char szRcvBuff[DEF_BUF_SIZE];
    SOCKADDR_IN SourceSockAddr;
    pICMPHeader->nCheckSum = GetCheckSum((LPBYTE)(ICMPPack), ICMP_HEADER_SIZE);
    sendto(s, ICMPPack, ICMP_HEADER_SIZE, 0, (SOCKADDR*)&addr, sizeof(addr));//将指定字节数的数据发送到指定的终结点
    int nLen = sizeof(SOCKADDR_IN);
    nRet = ::recvfrom(s, szRcvBuff,DEF_BUF_SIZE,0,(SOCKADDR*)&SourceSockAddr,&nLen);//接收目标IP的数据
    
if(nRet != SOCKET_ERROR) 

    SOCKET c=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//建立一个SOCKET
if (c==INVALID_SOCKET)//SOCKET返回值为INVALID_SOCKET错误退出连接
{
return -1;
}
DWORD dwset=1;
int ret=ioctlsocket(c,FIONBIO,(LPDWORD)&dwset); //用非阻塞的连接
if (ret==SOCKET_ERROR)//设置ioctlsocket返回值为SOCKET_ERROR 退出
{
return -1;
}
DWORD start=GetTickCount();
connect(c,(SOCKADDR*)&addr,sizeof addr);//创建一个计算机之间的通信

timeval timeout;
fd_set r;
FD_ZERO(&r);//总是这样先清空一个描述符集
FD_SET(c,&r); //把c放入要测试的描述符集 
timeout.tv_sec=1;//设置秒
timeout.tv_usec=0;//设置微秒

ret=select(0,0,&r,0,&timeout);
if (ret<=0) //超时或SOCKET_ERROR
{printf("%s   %d  Close \n",inet_ntoa(addr.sin_addr),x);}
else
    {printf("%s   %d  Open  \n",inet_ntoa(addr.sin_addr),x);}
dwset=0;
ret=ioctlsocket(c,FIONBIO,(LPDWORD)&dwset);
if (ret==SOCKET_ERROR)
{
printf("error %d\n",WSAGetLastError());
}
}
else {printf("%s   Not online\n",inet_ntoa(addr.sin_addr));}
}
else
{
ReleaseMutex(g_hMutex);
            break;
}
}
return 0;
}

10 个解决方案

#1


做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

#2


多线程的话,你可以分段扫描:
比如:第一个线程扫描192.168.1.1~192.168.1.50
第二个扫描:192.168.1.50~192.168.1.100
。。。。
另外,设置的超时可以短一点,你那1000太长了吧

#3


引用 2 楼  的回复:
多线程的话,你可以分段扫描:
比如:第一个线程扫描192.168.1.1~192.168.1.50
第二个扫描:192.168.1.50~192.168.1.100
。。。。
另外,设置的超时可以短一点,你那1000太长了吧

另外,如果是分段扫描,那么就可以不考虑线程同步
相比使用内核对象进行同步,速度快多了

#4


引用 3 楼  的回复:
引用 2 楼 的回复:
多线程的话,你可以分段扫描:
比如:第一个线程扫描192.168.1.1~192.168.1.50
第二个扫描:192.168.1.50~192.168.1.100
。。。。
另外,设置的超时可以短一点,你那1000太长了吧

另外,如果是分段扫描,那么就可以不考虑线程同步
相比使用内核对象进行同步,速度快多了

谢谢3楼的朋友我刚刚删除了WaitForSingleObject(g_hMutex, INFINITE); 
程序设置为60 超时设置为500 速度快了很多 但是开头都是192.168.1.1 这样的 为什么会这样? 高手能帮我修改一下吗

#5


引用 1 楼  的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE); 
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就出现了5个192.168.1.1
加着一段后WaitForSingleObject(g_hMutex, INFINITE); 
就避免了这样 要怎么修改才能提升速度很扫描正确

#6


引用 5 楼  的回复:
引用 1 楼 的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE); 
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就出现了5个192.168……

在CreateThread的时候,由 lpParameter传入参数i(for 循环创建线程时的i)
线程个数有n个,线程中有一个计数count的话:
第一段:n*count1 + i
第二段:n*count2 + i (i已经++)
。。。。。
这样就分段了,因为他们取模的话,模值是0~n-1

#7


引用 5 楼  的回复:
引用 1 楼 的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE); 
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就出现了5个192.168……


没有仔细看老兄的代码.
这里有点一般性的建议:
要优化代码,首先要确定耗时最长一个或多个点,用Profile类或者工具来测试时间,以确定热点.
之后对耗时最长的部分做改进.如果如此之后还是不能达到要求,有2种可能性:
1. 程序要做的事在现有的环境下至少都要消耗这么多的时间(时间下限);
2. 程序结构有问题,在现有结构再怎么优化都不可能达到要求,这样就要重新设计程序的代码结构.
   即使就这样140行代码也可能有这样的问题.
另外,对于使用同步对象,请仔细挑选,通常是优先使用用户级的同步对象,在必须的时候才使用内核
同步对象,原因在于内核对象的使用需要在内核空间运行,这样就有了从用户态切换到内核态,然后由
内核态返回到用户态的开销.

当然,我这里只是建议,这些动作不一定有效,毕竟我没有仔细的看代码.

#8


仅供参考
#include <windows.h>
#include <stdio.h>
char cmdstr[256];
int i;
int YN(int k) {
    FILE *f;
    char fn[40];
    char ln[80];
    int yn=0;

    sprintf(fn,"d:\\ping%d.txt",k);
    f=fopen(fn,"r");
    if (NULL!=f) {
        fgets(ln,80,f);
        fgets(ln,80,f);
        fgets(ln,80,f);
        if (1==fscanf(f,"Re%c",&yn)) yn='q'-yn;
        fclose(f);
        unlink(fn);
    }
    return yn;
}
void main() {
    for (i=115;i<130;i++) {
        sprintf(cmdstr,"cmd /c ping 192.168.2.%d -n 1 -w 1000 >d:\\ping%d.txt",i,i);
        WinExec(cmdstr,SW_HIDE);
    }
    Sleep(3000);
    for (i=115;i<130;i++) {
        printf("%d 192.168.2.%d\n",YN(i),i);
    }
}
//1 192.168.2.115
//0 192.168.2.116
//0 192.168.2.117
//0 192.168.2.118
//1 192.168.2.119
//0 192.168.2.120
//0 192.168.2.121
//0 192.168.2.122
//1 192.168.2.123
//0 192.168.2.124
//0 192.168.2.125
//1 192.168.2.126
//0 192.168.2.127
//1 192.168.2.128
//0 192.168.2.129

#9


引用 6 楼  的回复:
引用 5 楼 的回复:
引用 1 楼 的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE);
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就……

我是新手学多线程不久 很多都不懂 你说的我也不是很明白
你能修改一下代码吗 谢谢朋友了 

#10


引用 8 楼  的回复:
仅供参考

C/C++ code

#include <windows.h>
#include <stdio.h>
char cmdstr[256];
int i;
int YN(int k) {
    FILE *f;
    char fn[40];
    char ln[80];
    int yn=0;

    sprintf(fn,"d:\\ping%……

不懂。。。

#1


做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

#2


多线程的话,你可以分段扫描:
比如:第一个线程扫描192.168.1.1~192.168.1.50
第二个扫描:192.168.1.50~192.168.1.100
。。。。
另外,设置的超时可以短一点,你那1000太长了吧

#3


引用 2 楼  的回复:
多线程的话,你可以分段扫描:
比如:第一个线程扫描192.168.1.1~192.168.1.50
第二个扫描:192.168.1.50~192.168.1.100
。。。。
另外,设置的超时可以短一点,你那1000太长了吧

另外,如果是分段扫描,那么就可以不考虑线程同步
相比使用内核对象进行同步,速度快多了

#4


引用 3 楼  的回复:
引用 2 楼 的回复:
多线程的话,你可以分段扫描:
比如:第一个线程扫描192.168.1.1~192.168.1.50
第二个扫描:192.168.1.50~192.168.1.100
。。。。
另外,设置的超时可以短一点,你那1000太长了吧

另外,如果是分段扫描,那么就可以不考虑线程同步
相比使用内核对象进行同步,速度快多了

谢谢3楼的朋友我刚刚删除了WaitForSingleObject(g_hMutex, INFINITE); 
程序设置为60 超时设置为500 速度快了很多 但是开头都是192.168.1.1 这样的 为什么会这样? 高手能帮我修改一下吗

#5


引用 1 楼  的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE); 
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就出现了5个192.168.1.1
加着一段后WaitForSingleObject(g_hMutex, INFINITE); 
就避免了这样 要怎么修改才能提升速度很扫描正确

#6


引用 5 楼  的回复:
引用 1 楼 的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE); 
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就出现了5个192.168……

在CreateThread的时候,由 lpParameter传入参数i(for 循环创建线程时的i)
线程个数有n个,线程中有一个计数count的话:
第一段:n*count1 + i
第二段:n*count2 + i (i已经++)
。。。。。
这样就分段了,因为他们取模的话,模值是0~n-1

#7


引用 5 楼  的回复:
引用 1 楼 的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE); 
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就出现了5个192.168……


没有仔细看老兄的代码.
这里有点一般性的建议:
要优化代码,首先要确定耗时最长一个或多个点,用Profile类或者工具来测试时间,以确定热点.
之后对耗时最长的部分做改进.如果如此之后还是不能达到要求,有2种可能性:
1. 程序要做的事在现有的环境下至少都要消耗这么多的时间(时间下限);
2. 程序结构有问题,在现有结构再怎么优化都不可能达到要求,这样就要重新设计程序的代码结构.
   即使就这样140行代码也可能有这样的问题.
另外,对于使用同步对象,请仔细挑选,通常是优先使用用户级的同步对象,在必须的时候才使用内核
同步对象,原因在于内核对象的使用需要在内核空间运行,这样就有了从用户态切换到内核态,然后由
内核态返回到用户态的开销.

当然,我这里只是建议,这些动作不一定有效,毕竟我没有仔细的看代码.

#8


仅供参考
#include <windows.h>
#include <stdio.h>
char cmdstr[256];
int i;
int YN(int k) {
    FILE *f;
    char fn[40];
    char ln[80];
    int yn=0;

    sprintf(fn,"d:\\ping%d.txt",k);
    f=fopen(fn,"r");
    if (NULL!=f) {
        fgets(ln,80,f);
        fgets(ln,80,f);
        fgets(ln,80,f);
        if (1==fscanf(f,"Re%c",&yn)) yn='q'-yn;
        fclose(f);
        unlink(fn);
    }
    return yn;
}
void main() {
    for (i=115;i<130;i++) {
        sprintf(cmdstr,"cmd /c ping 192.168.2.%d -n 1 -w 1000 >d:\\ping%d.txt",i,i);
        WinExec(cmdstr,SW_HIDE);
    }
    Sleep(3000);
    for (i=115;i<130;i++) {
        printf("%d 192.168.2.%d\n",YN(i),i);
    }
}
//1 192.168.2.115
//0 192.168.2.116
//0 192.168.2.117
//0 192.168.2.118
//1 192.168.2.119
//0 192.168.2.120
//0 192.168.2.121
//0 192.168.2.122
//1 192.168.2.123
//0 192.168.2.124
//0 192.168.2.125
//1 192.168.2.126
//0 192.168.2.127
//1 192.168.2.128
//0 192.168.2.129

#9


引用 6 楼  的回复:
引用 5 楼 的回复:
引用 1 楼 的回复:
做同一件事情,多线程可能比单线程更慢,因为中间多了线程切换的开销.
当然,如果多个CPU同时去跑可能会更快.

朋友请问 要怎么修改? 我听agoago_2009修改后速度有些改善了
WaitForSingleObject(g_hMutex, INFINITE);
这段删除后速度就更快 但是 出现了很多192.168.1.1 5个线程就……

我是新手学多线程不久 很多都不懂 你说的我也不是很明白
你能修改一下代码吗 谢谢朋友了 

#10


引用 8 楼  的回复:
仅供参考

C/C++ code

#include <windows.h>
#include <stdio.h>
char cmdstr[256];
int i;
int YN(int k) {
    FILE *f;
    char fn[40];
    char ln[80];
    int yn=0;

    sprintf(fn,"d:\\ping%……

不懂。。。