windows C++ 通过UDP广播获取网络中所有设备ip地址

说明:

源码下载地址:http://download.csdn.net/detail/dxzysk/9756896

源码使用说明,先在需要获取IP地址的主机上运行server端程序,然后在需要搜索主机的Pc上运行client端程序

本文是windows版,VC++,在VS2010环境下调试成功。有时候需要搜索网络中的设备,机器,服务器等,这就要要用到UDP广播的方式,发送广播命令,广播给网络中的每一个主机,该主机或设备接收到广播命令后,立刻发送给请求端自己的设备信息,这里以IP信息为例子。

思路

在每一个设备中部署sever端程序进行监控,client端发送广播命令,每一个server收到命令后,返回给client自己的ip地址信息,给出代码如下,其中,有部分,比如获取ip地址参考来自网络,尊重原创,乐于分享。

server端(windows控制台程序)

server端监听广播命令”GetIPAddr”,收到命令后就相应


#include <WinSock2.h>  
#include <stdio.h>  
#include <iostream>   
using namespace std;  

#pragma comment(lib, "ws2_32.lib")   

#define GET_HOST_COMMAND "GetIPAddr"
const int MAX_BUF_LEN = 255;
#define SERVER_PORT 12811   

//只返回一个ip地址
bool GetLocalIP(char* ip)  
{  
    //1.初始化wsa  
    WSADATA wsaData;  
    int ret=WSAStartup(MAKEWORD(2,2),&wsaData);  
    if (ret!=0)  
    {  
        return false;  
    }  
    //2.获取主机名  
    char hostname[256];  
    ret=gethostname(hostname,sizeof(hostname));  
    if (ret==SOCKET_ERROR)  
    {  
        return false;  
    }  
    //3.获取主机ip  
    HOSTENT* host=gethostbyname(hostname);  
    if (host==NULL)  
    {  
        return false;  
    }  
    //4.转化为char*并拷贝返回  
    strcpy(ip,inet_ntoa(*(in_addr*)*host->h_addr_list));  
    return true;  
} 

bool doServer(){
    int m_nPort = SERVER_PORT;

    SOCKET sClient;
    sockaddr_in clientAddr,bindAddr;
    WSADATA wsdata;

    //启动SOCKET库,版本为2.0
    WORD    wVer=MAKEWORD(2,0);
    if( 0 != WSAStartup(wVer,&wsdata) )
    {
        //AfxMessageBox(L"Not Support Socket2.0");
        return false;
    }

    //用UDP初始化套接字
    sClient=socket(AF_INET,SOCK_DGRAM,0);
    //设置该套接字为广播类型,
    BOOL optval=TRUE;
    bindAddr.sin_family=AF_INET;
    bindAddr.sin_addr.s_addr=htonl(INADDR_ANY);
    bindAddr.sin_port=htons(m_nPort);
    setsockopt(sClient,SOL_SOCKET,SO_BROADCAST,(char FAR *)&optval,sizeof(optval));
    bind(sClient,(sockaddr *)&bindAddr,sizeof(sockaddr_in));

    int nAddrLen = sizeof(SOCKADDR);   
    char buf[256] = {0};
    int fromlength=sizeof(SOCKADDR);
    printf("the server is start.\n");

    char ipaddr[30] = {0};

    char buff[MAX_BUF_LEN] = ""; 
    if (GetLocalIP(ipaddr))
    {
        sprintf(buff, "my ip is:%s", ipaddr);   
    }
    else
    {
        sprintf(buff, "%s", "my ip is:******"); 
    }

    //有多个ip地址的时候,这样调用
    //IPInfo ips[10];
    //int len1 = 0;
    //GetLocalIPs(ips, 10,&len1);

    while(true)
    {
        int nRet = recvfrom(sClient,buf,256,0,(struct sockaddr FAR *)&clientAddr,(int FAR *)&fromlength);
        if( SOCKET_ERROR != nRet )
        {
            char    *pIPAddr = inet_ntoa(clientAddr.sin_addr);
            if( NULL != pIPAddr )
            {
                WCHAR    wzIPBuffer[32] = {0};
                printf("clientAddr: %s\n", pIPAddr);
                printf("receive command: %s\n", buf);
            }
            if (strcmp(buf,GET_HOST_COMMAND) != 0)
            {
                printf("the command not valid and was ignored.\n", buf);
                continue;
            }
            // 发送数据   
            int nSendSize = sendto(sClient, buff, strlen(buff), 0, (SOCKADDR*)&clientAddr, nAddrLen);   
            if(SOCKET_ERROR == nSendSize)   
            {   
                int err = WSAGetLastError();   
                printf("\"sendto\" error!, error code is %d\n", err);   
                return false;   
            }

        }
        else
        {
            //AfxMessageBox(L"Recv UDP Failed");
        }

        Sleep(1000);
    }

    closesocket(sClient);
    return true;
}

int main()
{
    if (!doServer())
    {
        printf("sever returned an error");
        return -1;
    }
    return 0;
}

注意上面是只有一个Ip地址的情况,有的机器可能会有多个IP地址,不同的网络,有线网,无线wifi等,需要获取多个ip地址的方法:

//结构体记录ip信息
typedef struct tagIPInfo  
{  
    char ip[30];  
}IPInfo;  

//获取多个ip地址信息列表
bool GetLocalIPs(IPInfo* ips,int maxCnt,int* cnt)  
{  
    //1.初始化wsa  
    WSADATA wsaData;  
    int ret=WSAStartup(MAKEWORD(2,2),&wsaData);  
    if (ret!=0)  
    {  
        return false;  
    }  
    //2.获取主机名  
    char hostname[256];  
    ret=gethostname(hostname,sizeof(hostname));  
    if (ret==SOCKET_ERROR)  
    {  
        return false;  
    }  
    //3.获取主机ip  
    HOSTENT* host=gethostbyname(hostname);  
    if (host==NULL)  
    {  
        return false;  
    }  
    //4.逐个转化为char*并拷贝返回  
    *cnt=host->h_length<maxCnt?host->h_length:maxCnt;  
    for (int i=0;i<*cnt;i++)  
    {  
        in_addr* addr=(in_addr*)*host->h_addr_list;  
        strcpy(ips[i].ip,inet_ntoa(addr[i]));  
    }  
    return true;  
} 

client端(windows控制台程序)

client端发送”GetIPAddr”命令,并及时接收client端发过来的信息


//#include "stdafx.h"  
#include <WinSock2.h>  
#include <stdio.h>  

#pragma comment(lib, "ws2_32.lib")   

const int MAX_BUF_LEN = 255;   

#define GET_HOST_COMMAND "GetIPAddr"
#define CLIENT_PORT 11121
#define SERVER_PORT 12811

int main()   
{   
    int nPort = SERVER_PORT;
    WORD wVersionRequested;   
    WSADATA wsaData;   
    int err;   

    // 启动socket api   
    wVersionRequested = MAKEWORD( 2, 2 );   
    err = WSAStartup( wVersionRequested, &wsaData );   
    if ( err != 0 )   
    {   
        return -1;   
    }   

    if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )   
    {   
            WSACleanup( );   
            return -1;    
    }   

    // 创建socket   
    SOCKET connect_socket;   
    connect_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);   
    if(INVALID_SOCKET == connect_socket)   
    {   
        err = WSAGetLastError();   
        printf("\"socket\" error! error code is %d\n", err);   
        return -1;   
    }   

    // 用来绑定套接字   
    SOCKADDR_IN sin;   
    sin.sin_family = AF_INET;   
    sin.sin_port = htons(CLIENT_PORT);   
    sin.sin_addr.s_addr = 0;   

    // 用来从网络上的广播地址接收数据   
    SOCKADDR_IN sin_from;   
    sin_from.sin_family = AF_INET;   
    sin_from.sin_port = htons(nPort);   
    sin_from.sin_addr.s_addr = INADDR_BROADCAST;   

    //设置该套接字为广播类型,   
    bool bOpt = true;   
    setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char*)&bOpt, sizeof(bOpt));   

    // 绑定套接字   
    err = bind(connect_socket, (SOCKADDR*)&sin, sizeof(SOCKADDR));   
    if(SOCKET_ERROR == err)   
    {
        err = WSAGetLastError();   
        printf("\"bind\" error! error code is %d\n", err);   
        return -1;   
    }   

    printf("the client is start.\n");
    int nAddrLen = sizeof(SOCKADDR);   
    char buff[MAX_BUF_LEN] = "";   
    int nLoop = 0;  

    char    szMsg[]=GET_HOST_COMMAND;
    int nLen=sizeof(sin_from);
    if( SOCKET_ERROR==sendto(connect_socket, szMsg, strlen(szMsg), 0, (sockaddr*)&sin_from, nLen) )
    {
       // AfxMessageBox(L"Send UDP Failed");  
        return -1;
    }

    printf("send broadcast data:%s\n", GET_HOST_COMMAND);

    while(true)   
    {   
        // 接收数据   
        int nSendSize = recvfrom(connect_socket, buff, MAX_BUF_LEN, 0, (SOCKADDR*)&sin_from, &nAddrLen);   
        if(SOCKET_ERROR == nSendSize)   
        {   
            err = WSAGetLastError();   
            printf("\"recvfrom\" error! error code is %d\n", err);   
            return -1;   
        }   
        buff[nSendSize] = '\0';   
        printf("received ip: %s\n", buff);   
    }   

    return 0;   
}  

运行结果

  • 1.Server端
    这里写图片描述
  • 2.Client端
    这里写图片描述
    运行结果说明:两个ip地址一样,是因为client和server我都运行在同一台机器上,如果有多台server,则client可以搜素到多个ip,受到条件限制,这里只有一个。
  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
以下是一个简单的 Linux C++ UDP 广播服务端示例: ```cpp #include <iostream> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> using namespace std; int main() { const int PORT = 8888; // 广播端口 const char* BROADCAST_IP = "255.255.255.255"; // 广播IP地址 // 创建socket int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket error"); exit(1); } // 设置广播选项 int on = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { perror("setsockopt error"); exit(1); } // 设置服务器地址 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); // 清空结构体 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = inet_addr(BROADCAST_IP); // 送数据 const char* msg = "Hello, world!"; if (sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("sendto error"); exit(1); } // 关闭socket close(sockfd); return 0; } ``` 说明: 1. 创建 socket 时使用 `AF_INET` 表示使用 IPv4 地址族,使用 `SOCK_DGRAM` 表示使用 UDP 协议。 2. 使用 `setsockopt` 函数设置 `SO_BROADCAST` 选项为 1,表示允许广播数据。 3. 设置服务器地址时,将 IP 地址设置为广播地址 `"255.255.255.255"`,表示将数据送给局域网内的所有设备。 4. 送数据时使用 `sendto` 函数,其第一个参数是 socket 文件描述符,第二个参数是要送的数据,第三个参数是数据长度,第四个参数是服务器地址信息,第五个参数是服务器地址信息的长度。 5. 关闭 socket 时使用 `close` 函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值