1. 程式人生 > >windows C++ 通過UDP廣播獲取網路中所有裝置ip地址

windows C++ 通過UDP廣播獲取網路中所有裝置ip地址

說明:

原始碼使用說明,先在需要獲取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,受到條件限制,這裡只有一個。