广播搜寻服务器的动态IP

我服务器放在景区镇上租的住处里,附近经常因为施工或是乱开挖之类的导致断电。我用的电信宽带。每次断电之后服务器自动重启就得重新分配一个ip。因为用了域名服务,重启后能根据域名查询到新的IP。

但是,我还是尝到了几次找不到服务器IP的苦头。有次在实验室通宵,准备连接上屋里的服务器做测试,因为以前觉得域名很方便就没有做记录IP的工作。结果就发现连不上了,打电话问住同一小区的朋友是不是停电了,结果根本就没有停电。登陆到我所使用的域名服务器的官网,才发现域名服务器瘫痪了,要维修两天。我特地买了大堆吃的到实验室准备利用两个不同的网络环境通宵做测试的,结果因为不知道服务器的IP,什么事情都做不了。自己有尝试用一些以前用过的IP去暴力连接,但都失败了。深更半夜的,想回去也没办法。于是开撸...

这种情况我遇上了很多次,但每次都没有办法。因为用的免费的域名服务,不可能给我多完善的服务。于是自己想办法解决这个问题。目前想了以下这几种办法:

1、使用2种以上不同的域名服务器。(该方法可行,服务器主机支持,路由器只支持某一个域名服务器)

2、使用一些手段通知自己更新后的IP。(正好我之前写过邮件服务器,可以通过这种方法,当我IP改变时或定时向我的一些邮箱发送服务器的当前IP,这方法不错,但是有些担心邮件发多了又要被那些小气的邮件服务器当成垃圾邮件把我拉黑。当我域名出现问题时,也通不过一些服务器的域名验证)

3、服务器上登个QQ。(哈哈,居然有这么NB的办法,而且真的很有用呢,IP是准的,QQ的服务器基本不会停机维护。但还是不完美,有时候登陆时间长了或是自动登陆失败后需要手动输入验证码,这就没辙了,因为PPPOE登陆实在路由器上,有时候服务器开机了路由器还没有登陆,就会出现QQ登陆不上的问题,这种情况设置下登陆延时应该就没问题了)

4、询问服务器所属网段类的所有IP地址。(因为无论怎么重新分配IP,他的大的网段都不会变的。我查了查,我那的地址始终是118.112-113.0.0的网段。)

对比之下,还是4这种自力更生的方法适合我,我直接做一个C/S结构的搜索程序就行了。2*256*256=131072。最多才十多万个可能的IP,分分钟就能找到我的服务器。设计的原理是:服务器这边始终监听着一个专用端口,用来接收客户端发过来的询问。如果询问信息和服务器最初设置的口令一致,服务器便向该地址回复同样的信息。客户端收到服务器相同的回复后,便能认定该地址就是要找的服务器IP地址。

因为改程序不需要占用太多资源,且需要跟着系统一起运行。我就直接在控制台实现,因为客户端需要像大量不同的IP发送信息,因此我使用非阻塞的UDP来进行通信。

以下是服务端的实现代码:

#include<windows.h>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<winsock.h>

struct findinfo//发送的口令结构
{
    char name[32];
};

findinfo minfo;
SOCKET ssock;
sockaddr_in saddr;
unsigned short sport;
HANDLE sthreadhandle;
bool isendthread;
UINT opthread(LPVOID Param);
//#pragma comment(lib,"ws2_32.lib")
using namespace std;

bool init()//初始化口令信息与监听端口
{
    FILE *f;
    if(!(f=fopen("findinfo","r")))//初始化信息储存在文件findinfo中
    {
        puts("not find init file");
        return false;
    }
    fscanf(f,"%s%d",minfo.name,&sport);
    if(strlen(minfo.name)<1)
    {
        puts("init file error");
        return false;
    }
    printf("token:%s\nsport:%d\n",minfo.name,sport);
    fclose(f);
    return true;
}

bool setreg()//设置开机启动
{
    char procbuf[256];
    GetModuleFileName(GetModuleHandle(NULL),procbuf,sizeof(procbuf));
    printf("this proc at:%s\n",procbuf);
    HKEY key;
    int ret;
    ret=RegOpenKeyEx(
                     HKEY_LOCAL_MACHINE,
                     "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
                     0,
                     KEY_SET_VALUE,
                     &key
                     );
    if(ret!=0)
    {
        printf("regopenkey fail:%d\n",ret);
        return false;
    }
    ret=RegSetValueEx(
                      key,
                      "findipsever",
                      0,
                      REG_SZ,
                      (const unsigned char*)procbuf,
                      sizeof(procbuf)
                      );
    if(ret!=0)
    {
        printf("set reginfo fail:%d\n",ret);
        ret=RegCloseKey(key);
        return false;
    }
    ret=RegCloseKey(key);
    return true;
}
bool clearreg()//清除开机启动
{
    char procbuf[256];
    GetModuleFileName(GetModuleHandle(NULL),procbuf,sizeof(procbuf));
    printf("this proc at:%s\n",procbuf);
    HKEY key;
    int ret;
    ret=RegOpenKeyEx(
                     HKEY_LOCAL_MACHINE,
                     "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
                     0,
                     KEY_SET_VALUE,
                     &key
                     );
    if(ret!=0)
    {
        printf("regopenkey fail:%d\n",ret);
        return false;
    }
    RegDeleteValue(
                   key,
                   "findipsever"
                   );

    if(ret!=0)
    {
        printf("clear reginfo fail:%d\n",ret);
        ret=RegCloseKey(key);
        return false;
    }
    ret=RegCloseKey(key);
    return true;
}
int main(int argv,char* argc[])
{
    if(argv>1)//配置开机启动
    {
        if(argc[1][0]==‘-‘&&argc[1][1]==‘s‘)
        {
            if(setreg())
            {
                puts("set reg secc");
            }
            else
            {
                puts("set reg fail");
            }
            return 0;
        }
        if(argc[1][0]==‘-‘&&argc[1][1]==‘c‘)
        {
            if(clearreg())
            {
                puts("clear reg secc");
            }
            else
            {
                puts("clear reg fail");
            }
            return 0;
        }
    }
    if(argv>2)//配置口令和端口信息
    {
        FILE *f;
        if(!(f=fopen("findinfo","w+")))
        {
            puts("can‘t open init file");
            return -1;
        }
        fprintf(f,"%s\n%s",argc[1],argc[2]);
        fclose(f);

        printf("edit:%s %s  secc\n",argc[1],argc[2]);
        return 0;
    }
    if(!init())//初始化口令和端口信息
    {
        puts("init error");
        return -1;
    }

    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(1,0),&wsaData))
    {
        printf("start socket error\n");
        return -1;
    }

    ssock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//套接字使用UDP
    if(ssock==INVALID_SOCKET)
    {
        printf("create sock error\n");
        WSACleanup();
        return -1;
    }

    saddr.sin_family = AF_INET;
    saddr.sin_port= htons(sport);//设置为所配置的端口
    saddr.sin_addr.S_un.S_addr = INADDR_ANY;

    if(bind(ssock,(sockaddr *)&saddr,sizeof(sockaddr))==SOCKET_ERROR)
    {
        printf("bind error\n");
        WSACleanup();
        return -1;
    }

    sockaddr_in newaddr;
    int addrsize=sizeof(sockaddr);
    char *buf=new char[256];
    int buflen;
    findinfo *reinfo=new findinfo;

    //设置为非阻塞模式
    int iMode=1;
    ioctlsocket(ssock,FIONBIO,(u_long FAR*)&iMode);

    isendthread=false;
    puts("--------sever start---------");

    //开启控制线程
    sthreadhandle=CreateThread(
                 NULL,
                 0,
                 (LPTHREAD_START_ROUTINE)opthread,
                 NULL,
                 0,
                 NULL
                 );

    while(!isendthread)//循环监听
    {
        buflen=recvfrom(
                        ssock,
                        buf,
                        200,
                        0,
                        (sockaddr *)&newaddr,
                        &addrsize
                        );
        if(buflen>0)
        {
            buf[buflen]=‘\0‘;
            //puts(buf);
            reinfo=(findinfo *)buf;
            if(strcmp(minfo.name,reinfo->name)==0)//口令匹配成功后进行回复
            {
                printf("%s send an request\n",
                       inet_ntoa(newaddr.sin_addr));
                sendto(
                       ssock,
                       (char *)&minfo,
                       sizeof(minfo),
                       0,
                       (sockaddr *)&newaddr,
                       sizeof(sockaddr)
                       );
            }
        }
        Sleep(100);//休眠节约资源
    }
    puts("---------sever end----------");
    Sleep(500);
    puts("---------main exit----------");
    return 0;
}

UINT opthread(LPVOID Param)//控制线程
{
    puts("-----enter hide window------");
    //getchar();
    Sleep(20000);
    HWND dos=GetForegroundWindow();
    ShowWindow(dos,SW_HIDE);
    puts("------ernter end sever------");
    getchar();
    isendthread=true;
    return 0;
}

对我那台服务器而言,客户端最多只需要发送10万条询问即可完成查询,就当客户端的上行带宽是1M,一条询问最多0.1k,不计网卡的的处理速度的话,最多2分钟就能完成询问。考虑到网卡的处理速度以及上行带宽。客户端进行查询就只使用一条线程进行发送询问,一条接收回复。代码如下:

#include<windows.h>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<winsock.h>

using namespace std;

struct findinfo//发送的口令结构
{
    char name[32];
};

char resultip[512][20];//储存获取到的服务器恢复结果(考虑广播地址发送至目的地的回复)
int resultnum;

findinfo minfo;
SOCKET sock;
sockaddr_in saddr;
HANDLE sthreadhandle;
bool isendthread;
UINT opthread(LPVOID Param);

bool isipend(unsigned short *s1,unsigned short *s2)//判断查询的IP是否越界
{
    for(int i=0;i<4;i++)
    {
        if(s1[i]<s2[i])
        {
            return false;
        }
    }
    return true;
}

int main(int argv,char* argc[])
{
    if(argv<2)
    {
        puts("format error\nthe right format: token port? startip? endip?");
        exit(-1);
    }
    strcpy(minfo.name,argc[1]);

    unsigned port=998;
    unsigned short sip[5];
    unsigned short eip[5];

    //查询至少带有口令参数,缺省:端口 开始ip 结束ip
    //默认:998端口 0.0.0.0-255.255.255.255
    if(argv>2)
    {
        port=atoi(argc[2]);
    }
    if(argv>3)
    {
        sscanf(argc[3],"%u.%u.%u.%u",
               sip,sip+1,sip+2,sip+3);
        //printf("%s %u %u %u %u\n",argc[3],sip[0],sip[1],sip[2],sip[3]);
    }
    else
    {
        for(int i=0;i<4;i++)
        {
            sip[i]=0;
        }
    }
    if(argv>4)
    {
        sscanf(argc[4],"%u.%u.%u.%u",
               eip,eip+1,eip+2,eip+3);
    }
    else
    {
        for(int i=0;i<4;i++)
        {
            eip[i]=255;
        }
    }

    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(1,0),&wsaData))
    {
        printf("start socket error\n");
        return -1;
    }

    sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//使用UDP套接字
    if(sock==INVALID_SOCKET)
    {
        printf("create sock error\n");
        WSACleanup();
        return -1;
    }

    //设置UDP非阻塞
    int iMode=1;
    ioctlsocket(sock,FIONBIO,(u_long FAR*)&iMode);

    //开启接收应答线程
    sthreadhandle=CreateThread(
                 NULL,
                 0,
                 (LPTHREAD_START_ROUTINE)opthread,
                 NULL,
                 0,
                 NULL
                 );

    saddr.sin_family = AF_INET;
    saddr.sin_port= htons(port);
    char cryip[20];

    /*saddr.sin_addr.S_un.S_addr = inet_addr("192.168.0.155");
    sendto(sock,(char *)&minfo,sizeof(minfo),0,(sockaddr *)&saddr,sizeof(sockaddr));*/
    puts("-----------start  find-------------");
    while(!isipend(sip,eip))//开始发送询问信息
    {
        sprintf(cryip,"%u.%u.%u.%u",
                sip[0],sip[1],sip[2],sip[3]);
        saddr.sin_addr.S_un.S_addr = inet_addr(cryip);
        sendto(sock,(char *)&minfo,sizeof(minfo),0,(sockaddr *)&saddr,sizeof(sockaddr));

        //修改到下一个IP
        sip[3]++;
        for(int i=3;i>0;i--)
        {
            if(sip[i]>255)
            {
                sip[i]=0;
                sip[i-1]++;
                printf("now at: %s\n",cryip);
            }
        }
    }

    Sleep(2000);
    puts("--------send find info end---------");
    puts("-------enter check result----------");

    getchar();
    isendthread=true;
    Sleep(500);

    closesocket(sock);
    puts("------------main  exit--------------");
    return 0;
}

UINT opthread(LPVOID Param)
{
    char *buf=new char[256];
    int buflen;
    findinfo *reinfo;
    sockaddr_in newaddr;
    int addrlen=sizeof(sockaddr);
    resultnum=0;

    isendthread=false;
    //printf("recvfrom start");
    while(!isendthread)//接收服务器的回复
    {
        buflen=recvfrom(
                        sock,
                        buf,
                        200,
                        0,
                        (sockaddr *)&newaddr,
                        &addrlen
                        );
        if(buflen>0)
        {
            buf[buflen]=‘\0‘;
            //puts(buf);
            reinfo=(findinfo *)buf;
            //如果接收到正确的回复,就将回复的IP地址存入结果字符串数组
            if(strcmp(minfo.name,reinfo->name)==0)
            {
                strcpy(resultip[resultnum++],inet_ntoa(newaddr.sin_addr));
                printf("find an addr at: %s\n",
                       resultip[resultnum-1]);
            }
        }
        //Sleep(100);
    }

    if(resultnum==0)
    {
        puts("not find any ip");
    }
    else
    {
        for(int i=0;i<resultnum;i++)
        {
            printf("find an addr at: %s\n",
                       resultip[i]);
        }
    }
    /*getchar();
    isendthread=true;*/
    puts("--------recvfrom thread end--------");
    return 0;
}

下面看下使用效果:

服务器首先要配置口令和端口,直接带上口令和端口参数即可

服务器使用参数:-s 配置开机启动 -c清除开机启动

自己运行即可开始服务

客户端查询至少带有口令参数,缺省:端口 开始ip 结束ip。默认:998端口 0.0.0.0-255.255.255.255

例如我要查询口令上面的服务器,参数为:wchrt 998 118.112.0.0 118.113.255.255

如图:

程序开始逐个IP进行询问,我这的运行速度是每秒查询1000个左右

查询完毕,发现了服务器所在的IP地址:118.112.50.14.查询成功

时间: 2024-10-23 17:51:48

广播搜寻服务器的动态IP的相关文章

成功使用自家服务器+ADSL动态IP绑定域名

系统:win7+Ubuntu 14.04网络设置:千兆网卡外网:100M家用光纤无固定IP路由:Mikrotik ROS RB951Ui-2HnD 内网路由:192.168.88.1 内网linux系统IP:192.168.88.89 已安装好lnmpa,还未建立虚拟主机 本来用花生壳弄,但设置太麻烦所以放弃了,找到了NAT123,虽然是免费级,但操作相对容易 Linux系统本来用CentOS,但怎么都装不上MONO,不知何解,所以转向用Ubuntu NAT123支持的功能很多,有远程开机域名映

android 发送UDP广播,搜寻服务器建立socket链接

应用场景:客户端(手机,pc)需要搜寻所在局域网内的服务器并获得服务器地址. 方法简介:客户端发送UDP广播,服务收到广播后得到客户端ip地址,然后向客户端发送一次socket链接,客户端收到socket链接,获得服务器地址. 相关知识: UPD.TCP.TCP是面向链接的,可靠的通信方式.UDP是面向非链接的通讯方式.TCP的建立比较麻烦,要经过"三次握手".而UDP的建立比较简单,发送方只管把内容发送出去,不管接收方是否收到.UDP的传输分为:单播,多播,广播.其中,多播和广播是通

2-3-配置DHCP服务器实现动态地址分配

学习一个服务的过程: 1.  此服务的概述:名字,功能,特点,端口号 2.  安装 3.  配置文件的位置 4.  服务启动关闭脚本,查看端口 5.  此服务的使用方法 6.  修改配置文件,实战举例 7.  排错(从下到上,从内到外) 本节所讲内容: ?        DHCP服务器工作原理 ?        使用DHCP为局域网中的机器分配IP地址 ?        使用DHCP为服务器分配固定IP地址 实验环境: 服务端:xuegod63.cn   IP:192.168.1.63 客户端:

架设自己的私有github+数据中心,并通过域名访问(支持adsl动态ip)

如果可以随时随地,用任何设备(手机电脑ipad)访问自己的所有工程,以及数据文件.歌曲.电影.照片等等,那该有多诱人呀,下面介绍一下具体方法. 安装环境:ubuntu server 14.04 1:安装gitlab(开源的版本管理服务器,模仿github写的) 下载安装gitlab 官方说明文档:https://about.gitlab.com/downloads/ 安装gitlab前,首先需要安装openssh和postfix,如果安装系统选择软件包时直接选上openssh-server,这时

ubuntu14.04静态ip地址与动态ip地址配置

有时我们希望Ubuntu14.04的ip地址为静态ip地址,使得ubuntu中的ip地址不变,这样会方便在嵌入式设备和主机Ubuntu进行用网口进行调试. 静态ip地址的配置方法:在/etc/network/interfaces文件中,修改内容为 # interfaces(5) file used by ifup(8) and ifdown(8) auto lo iface lo inet loopback auto eth0 iface eth0 inet static #iface eth0

iptables 自动绑定动态IP

由于公司的svn服务器放在外网,为了安全只允许特定的IP才能访问.(公司用PPPOE拨号) 几乎每天都要去刷公司的IP,这样很不方便.于是就想通过自动刷新动IP的想法. 具备条件: 1.路由器DDNS服务,如果没有那就用电脑下载花生壳客户端. 实现动态刷新shell核心代码如下: dyIP=$(ping **.kmdns.net -c1 | grep PING | awk '{ print $3 }' | cut -c 2- | cut -d\) -f1)iptables -A INPUT -s

阿里云域名解析到动态ip

UpgradeDNS 脚本下载 git clone https://github.com/X-Mars/UpgradeDNS.git 功能介绍 用于将阿里云解析到动态ip如果服务器位于 动态公网ip 的环境,那么多数用户在使用 花生壳 等第三方实现动态域名解析,速度慢,最主要二级或者多级域名 不专业 !如果你刚好使用了阿里云的域名云解析,那么此时,你可以使用本脚本实现 一级域名 的动态解析了. 使用方法 安装 python2.7 (必须) 安装阿里云api的python sdk pip2.7 i

香港多IP站群服务器-搭建多IP代理服务器、游戏加速服务器

耀磊花楹qq82521463香港WK自营机房多IP服务器租用,多IP站群服务器,多IP多C段 站群服务器租用 耀磊数据拥有3万个自由香港IP以及独立AS号,是APNIC核心成员,机房通过BGP融合 多条线路直连PCCW.NWT.PACNET.中国电信(香港CN2)等大型ISP服务商.对中国大 陆.亚太.北美乃至全球都有良好的网络表现,欢迎携手合作! 1.耀磊数据香港WK机房提供海量IP,支持多C段,5IP-258IP,4C段,8C段等,可以 满足用户对多IP服务器的需求,适合搭建代理服务器.游戏

linux hosts.allow 只允许adsl动态ip登录

[场景]公司采用ADSL拨号上网,即上网获得是动态IP. 服务器安全策略升级,只允许公司内可以访问服务器. 实现过程: 服务器指定固定IP可以访问服务器,其实很容易,一般有以下三下方法: 方法一: 在/etc/hosts.allow中添加允许ssh登陆的ip或者网段     sshd:192.168.1.2:allow 或者 sshd:192.168.1.0/24:allow  在/etc/hosts.deny添加不允许ssh登陆的IP sshd:ALL           #ALL表示除了上面