概述
说明:
源码下载地址: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: %sn", pIPAddr);
printf("receive command: %sn", 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 %dn", 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 %dn", 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 %dn", 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:%sn", 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 %dn", err);
return -1;
}
buff[nSendSize] = '