1. 自动计算当前局域网IP段 

  2. 多线程扫描

  3. 输出每个存活主机的IP和MAC地址,以及存活的总数(不带网卡厂商信息)

缺点:

  1. 自动获取区域网IP段 不可控IP 比如我扩大子网范围

  2. 遇到双网卡的情况下默认只扫描一个

///自动扫描局域网存活主机//优点:不用输入ip//缺点:如果遇到主机多IP只能扫描其中一个#include 
#include 
#include 
#pragma comment (lib,"ws2_32.lib")  #pragma comment (lib,"iphlpapi.lib")// 线程参数结构体 struct CThreadParam{        UINT uIp;                        // 整数的ip地址        HANDLE hEventCopy;  // 赋值参数的事件};CRITICAL_SECTION cs;        // 打印时用到的临界区UINT uTotal = 0;                // 输出一共存活的主机/// 用户扫描单个主机的线程函数DWORD WINAPI LanScan(LPVOID param)    {        HRESULT result;        CThreadParam cParam;        ULONG c[2] = {0},len=6;        cParam = *(CThreadParam *)param;        SetEvent(cParam.hEventCopy);        // 这句关键        result = SendARP(htonl(cParam.uIp),NULL,c,&len);        //发送ARP包        // 没有错误就输出        if(result == NO_ERROR)        {                UINT i;                BYTE *g = (BYTE *)&c;                in_addr target_addr;                target_addr.S_un.S_addr=htonl((cParam.uIp));                if (len)                 {                        ::EnterCriticalSection(&cs);                        printf("host %s living, max address:", inet_ntoa(target_addr));                        for (i = 0; i < (int) len; i++)                        {                                if (i == (len - 1))                                {                                        printf("%.2X\n", (int) g[i]);                                }                                else                                {                                        printf("%.2X-", (int) g[i]);                                }                        }                        uTotal++;                        ::LeaveCriticalSection(&cs);                }        }         return 0;}int main(){        // 初始化socket        WSADATA data;        WORD wVersion = MAKEWORD(2,2);                WSAStartup(wVersion,&data);        hostent *pLocalHost;        HANDLE hEvent;        // 获得本机IP结构        pLocalHost = ::gethostbyname("");        // 这样获得是网络字节序        ULONG ulIpAddress = (*(struct in_addr *)*(pLocalHost->h_addr_list)).S_un.S_addr;        PIP_ADAPTER_INFO pAdapterInfo=NULL;        ULONG ulLen=0;        // 为适配器结构申请内存        ::GetAdaptersInfo(pAdapterInfo,&ulLen);        pAdapterInfo=(PIP_ADAPTER_INFO)::GlobalAlloc(GPTR,ulLen);        // 初始化线程里用到的参数        ::InitializeCriticalSection(&cs);        hEvent = ::CreateEventW(NULL, FALSE, FALSE, NULL);        CThreadParam cParam;        //取得本地适配器结构信息        if(::GetAdaptersInfo(pAdapterInfo,&ulLen)==ERROR_SUCCESS)        {                while (pAdapterInfo!=NULL)                {                        if (::inet_addr(pAdapterInfo->IpAddressList.IpAddress.String) == ulIpAddress)                        {                                // 这里要转换为主机字节序                                ULONG ulIpMask = ntohl(::inet_addr(pAdapterInfo->IpAddressList.IpMask.String));                                // 与获得网络号                                ULONG ulNetName = ntohl(ulIpAddress) & ulIpMask;                                // 取非减2获得这个网段的主机数                                UINT unNum = ~ulIpMask;                                UINT nNumofHost = unNum - 2;                                // 循环把主机的IP带入线程进行扫描                                UINT i;                                HANDLE hThread;                                DWORD wThread;                                for (i = 0; i < nNumofHost; i++)                                {                                        // 存的都是主机字节序                                        cParam.uIp = ulNetName + i + 1;                                        cParam.hEventCopy = hEvent;                                        hThread = CreateThread(NULL, 0, LanScan, (LPVOID)&cParam, 0, &wThread);                                        ::WaitForSingleObject(hEvent, INFINITE);                                }                                break;                        }                         pAdapterInfo = pAdapterInfo->Next;                }        }        // 休息5秒,等待线程执行结束        Sleep(5000);        printf("\ntotal = %d\n", uTotal);        return 0;}

 VS2008下编译的,如果用vc6.0要加SDK才有相关的头文件。