【问题标题】:sendarp with multithreading function is not working for whole subnet (wifi environment)具有多线程功能的 sendarp 不适用于整个子网(wifi 环境)
【发布时间】:2015-11-26 13:21:08
【问题描述】:

我试图获取 WiFi 环境(整个子网)中所有设备的 Mac 地址。

最初,当我运行代码大约需要 10 分钟才能获得整个子网的结果,所以为了减少我在 Windows 机器中使用多线程概念的时间,但这种方法根本不起作用。

我在下面粘贴代码 sn-p。 即使我尝试了不同的逻辑,例如一次运行 255、100、50 ,2 个线程,但仍然失败。

我怀疑其中存在同步问题,但我不知道如何解决此问题,所以请帮助我完成此操作。

DWORD WINAPI GetMacAddrOfSubNet(LPVOID lpParam)
{

   DWORD dwRetVal;
   IPAddr DestIp = 0;
   IPAddr SrcIp = 0;       /* default for src ip */
   ULONG MacAddr[2];       /* for 6-byte hardware addresses */
   ULONG PhysAddrLen = 6;  /* default to length of six bytes */
   char look[100];

   strcpy(look ,(char *)lpParam);
   DestIp = inet_addr(look);

   memset(&MacAddr, 0xff, sizeof (MacAddr)); 
   /*Pinging particular ip and retrning mac addrs if response is thr*/
   dwRetVal = SendARP(DestIp, SrcIp, &MacAddr, &PhysAddrLen);
   if (dwRetVal == NO_ERROR) 
   {
       /**/ 
   } 
   return 0;
}

extern "C" __declspec(dllexport) int __cdecl PopulateARPTable(char *IpSubNetMask)
{

   char ipn[100];
   char buffer[10];
   unsigned int k;
   DWORD   dwThreadIdArray[260];
   HANDLE  hThreadArray[260]; 

   /*Run 255 threads at once*/
   for (k=1; k<255; k++)
   {
       itoa(k, buffer, 10);
       strcpy(ipn, IpSubNetMask);
       strcat(ipn, "."); 
       strcat(ipn, buffer);

       /*Thread creation */
       hThreadArray[k] = CreateThread( NULL, 0, GetMacAddrOfSubNet, ipn, 0, &dwThreadIdArray[k]);
       if (hThreadArray[k] == NULL) 
       {           
          //ExitProcess(3);
       }
   }
   WaitForMultipleObjects(255, hThreadArray, TRUE, INFINITE);

   return 0;

}

【问题讨论】:

  • 请不要标记垃圾邮件,这不是 C++,我已经为您修复了标签

标签: c windows multithreading


【解决方案1】:

ipn 缓冲区只存在一次。您正在使用和修改它作为(最多)255 个线程的参数。并且您希望线程中的语句strcpy(look ,(char *)lpParam) 将在主线程修改ipn 再次调用下一个线程之前执行。但事实并非如此,至少不能保证。所以你的线程可能使用了错误的参数。

要么为每个线程使用不同的缓冲区,要么实现同步,以确保在主线程再次修改缓冲区之前,线程已经复制了参数。

【讨论】:

  • 您好,感谢您的快速响应,我为每个线程使用了不同的缓冲区,但这次只有很少的响应返回。(预期结果是差异)。我确实找到了实现相同目标的不同方法,所以再次感谢您的努力
【解决方案2】:

我已经为 Excel 完成了这项工作,编写了一个多线程 DLL,除了获取 MAC 地址之外,它还会执行 DNS 反向主机名和 ICMP ping RT。

让我知道您是否需要随附的 VBA 代码。基于 C 的 DLL(您可能会喜欢作为模板)的来源是:

/* 
    ExcelNet library: Provide threaded networking functions 
    NOTE: Serially doing these on the network involves serially waiting for timeouts, much ouchies!
    
    Written by: Danny Holstein
 */
#if 1   //  header stuff
#include <windows.h>
#include <iphlpapi.h>
#include <icmpapi.h>

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

#define MSEXPORT __declspec(dllexport)

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

#define BUFSZ 256
typedef struct {
    char ip[BUFSZ];     //  IP addresses in dotted notation.
    int ipSize;         //  size of IP address buffer
    char data[BUFSZ];   //  general network data (MAC, hostname, etc)
    int dataSize;       //  size of data buffer ^
    int err_no;         //  WinAPI error number
    int (*func)(LPCSTR Addr, char* buf, int BufSz); //  function address, &GetNameInfos, &GetARP or &GetICMP
} NET_DATA;

int GetARP(LPCSTR Addr, char* Buf, int BufSz);
int GetNameInfos(LPCSTR Addr, char* Buf, int BufSz);
int GetICMP(LPCSTR Addr, char* Buf, int BufSz);

char msg_dbg[BUFSZ], dan[BUFSZ];
#define DEBUG_PRT() {snprintf(msg_dbg, BUFSZ, "lineno = %d\tfunc = %s", __LINE__ , __func__); MessageBox(0, msg_dbg, "debug", 0);}
#define DEBUG_MSG(msg) {snprintf(msg_dbg, BUFSZ, "msg=\"%s\"\tlineno = %d\tfunc = %s", msg, __LINE__ , __func__); MessageBox(0, msg_dbg, "debug", 0);}

#if 0   //  documentation indicates malloc/realloc/free shouldn't be used in DLLs
    #define malloc(A) malloc(A)
    #define realloc(A, B) realloc(A, B)
    #define free(A) free(A)
    // #define NOMEMLEAK    //  dudint work
#else   //  kinda works, when NOT allocating all the NET_DATA structure elements
    #define malloc(A) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, A)
    #define realloc(A, B) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, A, B)
    #define free(A) (void) HeapFree(A, HEAP_GENERATE_EXCEPTIONS, NULL)
    #define NOMEMLEAK
#endif
#endif
MSEXPORT  void __stdcall ArrayDGH(SAFEARRAY **IntArr, SAFEARRAY **StrArr)
{
    SAFEARRAY *A = (SAFEARRAY*) (*IntArr);
    SAFEARRAY *S = (SAFEARRAY*) (*StrArr);
    int n = (*A).rgsabound[0].cElements;
    
    snprintf(dan, BUFSZ, "a num elems = %d, str num elems = %d", n, (*S).rgsabound[0].cElements); DEBUG_MSG(dan);
    // for (int i=0; i<n; i++) {snprintf(dan, BUFSZ, "elem[%d] = %d", i, ((int*) (*A).pvData)[i]); DEBUG_MSG(dan);}
    OLECHAR* str[] = {L"Da",L"Fuk",L"Waz",L"Dat?",L"dot",L"dot"};
    for (int i=0; i<n; i++) {SysReAllocString(&(((BSTR*) (*S).pvData)[i]), str[i]);}
}

DWORD dwMilliseconds = 10000;

MSEXPORT  void __stdcall SetTIMO(DWORD Timo) {dwMilliseconds = Timo;}

MSEXPORT  bool __stdcall ExcelSendARP(LPCSTR Addr, BSTR* MAC)
{
    char buf[BUFSZ];
    int err = GetARP(Addr, buf, BUFSZ);
    *MAC = SysAllocStringByteLen(buf, strlen(buf)); //  avoid WIDE to ANSI stuff
    return !err;
}

MSEXPORT  bool __stdcall ExcelICMPRT(LPCSTR Addr, BSTR* RoundTrip)
{
    char buf[BUFSZ];
    int err = GetICMP(Addr, buf, BUFSZ);
    *RoundTrip = SysAllocStringByteLen(buf, strlen(buf));   //  avoid WIDE to ANSI stuff
    return !err;
}

MSEXPORT  bool __stdcall ExcelGetNameInfo(LPCSTR Addr, BSTR* NameInfo)
{
    char buf[BUFSZ];
#ifdef TEST_FUNC_PTR
    int (*FunAddr[2])(LPCSTR Addr, char** buf, int BufSz);
    FunAddr[0] = &GetARP; FunAddr[1] = &GetNameInfos;  //  DRY code hooks
    int err = (*(FunAddr[1]))(Addr, buf, BUFSZ);
#else
    int err = GetNameInfos(Addr, buf, BUFSZ);
#endif

    *NameInfo = SysAllocStringByteLen(buf, strlen(buf));    //  avoid WIDE to ANSI stuff
    return !err;
}

int GetNameInfos(LPCSTR Addr, char* buf, int BufSz)
{
    ULONG inet; DWORD resp = 0; HOSTENT *tHI;
    struct in_addr addr = { 0 };
    
    if ((inet = inet_addr(Addr)) == INADDR_NONE) {
        if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
        return inet;
    }
    
    addr.s_addr = inet; tHI = gethostbyaddr((char *) &addr, 4, AF_INET);
    if (tHI == NULL) {  //  no reponse for this IP condition, decode condition and place in PCHAR buf
        resp =  WSAGetLastError();
        FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
        return resp;
    }
    
    _snprintf_s(buf, BufSz-1, _TRUNCATE, "%s", tHI->h_name);    //  place hostname in PCHAR buf
    return resp;    //  <- resp = 0, we have a hostname associated with this IP, SUCCESS!
}

int GetARP(LPCSTR Addr, char* buf, int BufSz)
{
#define BUFLEN 6
    ULONG pMacAddr[BUFLEN], inet, BufLen = BUFLEN; DWORD resp = 0;
    if ((inet = inet_addr(Addr)) == INADDR_NONE) {
        if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
        return inet;
    }
    resp = SendARP(inet, 0, pMacAddr, &BufLen);
    if (resp) { //  no reponse for this IP condition, decode condition and place in PCHAR buf
        FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
        return resp;
    }
    
    UCHAR *pMacAddrBytes = (UCHAR *) pMacAddr;
    _snprintf_s(buf, BufSz, _TRUNCATE, "%02x:%02x:%02x:%02x:%02x:%02x", pMacAddrBytes[0], pMacAddrBytes[1], pMacAddrBytes[2],
                                                                        pMacAddrBytes[3], pMacAddrBytes[4], pMacAddrBytes[5]);  //  place MAC in PCHAR buf
    return resp;    //  <- resp = 0, we have a MAC associated with this IP, SUCCESS!
}

int GetICMP(LPCSTR Addr, char* buf, int BufSz)
{
    HANDLE hIcmpFile;
    ULONG inet; DWORD resp = 0;
    char SendData[] = "Data Buffer";
    LPVOID ReplyBuffer = NULL;
    DWORD ReplySize = 0;
    
    if ((inet = inet_addr(Addr)) == INADDR_NONE) {
        if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
        return inet;
    }

    hIcmpFile = IcmpCreateFile();
    if (hIcmpFile == INVALID_HANDLE_VALUE) {
        resp =  GetLastError();
        FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
        return resp;
    }
    
    // Allocate space for at a single reply
    ReplySize = sizeof (ICMP_ECHO_REPLY) + sizeof (SendData) + 8;
    ReplyBuffer = (VOID *) malloc(ReplySize);
    
    resp = IcmpSendEcho2(hIcmpFile, NULL, NULL, NULL,
                         inet, SendData, sizeof (SendData), NULL,
                         ReplyBuffer, ReplySize, dwMilliseconds);
    PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY) ReplyBuffer;                    
    if (resp == 0) {    //  no reponse for this IP condition, decode condition and place in PCHAR buf
        resp =  pEchoReply->Status; //  WSAGetLastError();
        FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
        return resp;
    }
    
    _snprintf_s(buf, BufSz-1, _TRUNCATE, "%d", ((PICMP_ECHO_REPLY) ReplyBuffer)->RoundTripTime);    //  place roundtrip time in PCHAR buf (ASCII representation)
    
    IcmpCloseHandle(hIcmpFile);
    return 0;   //  we have a RT time in milliseconds associated with this IP, SUCCESS!
}

NET_DATA *NetData;

DWORD WINAPI tGetDATA(LPVOID NetData)
{
    char buf[BUFSZ];
    NET_DATA *m = NetData;  //  stupid me, I had allocated the space, instead of address of, not thinking it all disappears on exit
    m->err_no = (*(m->func))(m->ip, buf, BUFSZ);    //  GetARP, GetNameInfos or GetICMP
    if (_snprintf_s(m->data, m->dataSize-1, _TRUNCATE, "%s", buf) == -1) DEBUG_MSG("_snprintf_s error!");
    //  A resources error may have hit AFTER the calling function has returned, including having the thread/memory deallocated in the calling function
    return 0;
}

MSEXPORT BSTR __stdcall ExcelRngNetData(UCHAR *list, ULONG *ErrNos, BSTR *DataArry, DWORD dwMilliseconds, char sep, char FunctType)
{   //  take list of IP addresses (newline-separated), create thread for each to get network data.  Return results in (sep-separated) BSTR.
    int i=0, j, NumIPs=0, k = strlen(list), l=0;
    #define NMSZ 100
    char nm[NMSZ];
    void* FuncAddr[3];  //  DRY code hooks
    FuncAddr[0] = &GetARP; FuncAddr[1] = &GetNameInfos; FuncAddr[2] = &GetICMP;
    
    while (i<k && sscanf_s(list+i, "%[^\n]\n", nm, NMSZ)){i += strnlen_s(nm, NMSZ) + 1; NumIPs++;}  //  count newline-separated items before doing malloc(), because realloc() is REALLY resource intensive
    
    NetData = malloc(NumIPs * sizeof(NET_DATA)); i = 0;
    while (i<k && sscanf_s(list+i, "%[^\n]\n", nm, NMSZ)){  //  load calling routines list into structures 
        j = strnlen_s(nm, NMSZ) + 1; i += j;
        NetData[l].err_no = WAIT_TIMEOUT;       //  easy way to preset the error to a TIMEOUT, if the thread successfully completes before the timeout, this will be set to reflect its timeout
        NetData[l].dataSize = BUFSZ;
        NetData[l].func = FuncAddr[FunctType];  //  DRY (Don't Repeat Yourself) code hook
        if (strncpy_s(NetData[l].ip, (NetData[l].ipSize = BUFSZ), nm, j)) DEBUG_MSG("strcpy_s error!");
        l++;
    }
    
    HANDLE  *tHandles = malloc(NumIPs * sizeof(HANDLE)); DWORD ThreadId;
    for (i=0; i<NumIPs; i++){
        tHandles[i] = CreateThread(NULL, 0, tGetDATA, &(NetData[i]), 0, &ThreadId);
        if (tHandles[i] == NULL) {DEBUG_MSG("Could not create threads!\nExiting now"); ExitProcess(3);}
    }
    if(WaitForMultipleObjects(NumIPs, tHandles, TRUE, dwMilliseconds) == WAIT_FAILED) {
        FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(), 0, dan, BUFSZ, 0); DEBUG_MSG(dan);
        //  Prolly means too many threads, kicked in when I exceeded 64; ERROR_INVALID_PARAMETER = "The parameter is incorrect"
    }
  
    #define CHUNK 1024
    #define DATASZ 256  //  tested with intentionally small size to check "safe" string functions
    wchar_t wcs[DATASZ]; char MacChunk[DATASZ];
    char *ans = malloc(CHUNK); int anslen = 0, anssz = CHUNK;
    char separator[2]; separator[0] = sep; separator[1] = 0;
    
    for(i=0; i<NumIPs; i++) {   //  build return BSTR and load array with data
        CloseHandle(tHandles[i]); ErrNos[i] = NetData[i].err_no;
        if (strncpy_s(MacChunk, DATASZ-1, NetData[i].err_no == 0 ? NetData[i].data : "", NetData[i].dataSize-1)) DEBUG_MSG("strcpy_s error!");
        if (i<NumIPs-1 && sep != 0) if (strncat_s(MacChunk, DATASZ-1, separator, 1)) DEBUG_MSG("strcpy_s error!");
        while (strnlen_s(MacChunk, DATASZ) > anssz - anslen -1) ans = realloc(ans, (anssz += CHUNK)); // choose CHUNK size to avoid constant realloc(), because realloc() is REALLY resource intensive
        if (strncpy_s(&(ans[anslen]), DATASZ-1, MacChunk, DATASZ-1)) DEBUG_MSG("strcpy_s error!"); anslen += strnlen_s(MacChunk, DATASZ);   //  return data in returned BSTR
        
        MultiByteToWideChar(CP_UTF8, 0,
                            ErrNos[i] == WAIT_TIMEOUT ? "The wait operation timed out." : NetData[i].data,
                            -1, wcs, DATASZ-1);    // return data in supplied array
        SysReAllocString(&DataArry[i], wcs); 
    }
    BSTR r = SysAllocStringByteLen(ans, strlen(ans));
    
#ifdef NOMEMLEAK
    free(NetData); free(tHandles); free(ans);
#endif

    return r;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-19
    • 2011-03-25
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 2019-09-21
    • 1970-01-01
    相关资源
    最近更新 更多