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

  2. 多线程扫描

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

缺点:

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

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

/////////////////////////////////////////
//自动扫描局域网存活主机
//优点:不用输入ip
//缺点:如果遇到主机多IP只能扫描其中一个
////////////////////////////////////////
#include <windows.h>
#include <stdio.h>
#include <iphlpapi.h>

#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才有相关的头文件。