近日为了满足2个屋子里人的通信需要,需要将本地的外网IP告诉给另一个屋子里的人。以前都是在群里喊一句,我这里的IP是XXXX,有一天自己突发奇想,想通过程序来实现这个自动化通知的过程。于是自己给自己定了需求。
需求:基本目标实现开机将本地的路由WAN口IP通知对方。
思考:如果才能实现自动通知呢?
首先,要有一个公共的空间,可以作为通知的载体。
其次,需要传输机制把通知发出去。
经过思考,我想到了电子邮件,邮箱是每个人都有的,email是可以用程度发的。于是需求变成了通过发邮件的方式把最新获取到的IP发出来。解决的思路有 了,最大的问题是如何获取外网IP,开始尝试获取本地IP,这个显然是没用的,因为机器是在内网环境,获取到的只是内网IP,后来试图想通过获取外网 IP,比如访问一个XXX网站的形式来获取IP,这种网站还真不少,但是获取到的都是公网IP,学过网络的人都知道公网IP很少,往往只是在网络节点上的 IP,这种IP对我一个ADSL用户来说几乎就没任何意义。其实我需要的只是路由的WAN口IP。网上搜了一下,也没找到合适的。在几乎绝望的时候,我想 到了代理,我能不能通过访问路由器的方式来获取IP呢,我试图用telnet登陆路由,试图用路由命令来操作路由,结果和我想象的一样,家用路由毕竟不是 服务器级别的路由,根本没有对外提供的访问命令,只能通过web的方式来实现对路由的设置。自己再次陷入了绝望,后来我打开fireBug,试图找到IP 那个查看IP跳转的页面。结果被我找到了,http://192.168.1.1/userRpm/StatusRpm.htm,点开页面查看响应,传过 来的就是网页的部分信息。OK,这就是我想要的IP。我突然兴奋起来,但是这似乎还不够,因为每次登陆路由时要输入用户名和密码。网上搜搜,这个其实不 难,代理服务程序就那样写的。经过一晚上的思考和实践WAN口IP算是被我搞出来了。
- package com.eehome.app.mail.utils;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.net.Authenticator;
- import java.net.URL;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import com.eehome.app.mail.IMailConstant;
- import com.eehome.app.mail.model.RouterPassAuth;
- /**
- * @author wensong
- * 2010-9-4 下午03:34:58
- */
- public class RouteIpUtils {
- private final static RouteIpUtils routeIpUtils = new RouteIpUtils();
- private RouteIpUtils() {
- }
- public static RouteIpUtils getInstance() {
- //验证器工具的实例进行注册
- Authenticator.setDefault(new RouterPassAuth());
- return routeIpUtils;
- }
- public String getRouteIp() throws IOException {
- StringBuffer wanPacket = getWanPacket();
- return getFirstIp(wanPacket);
- }
- /**
- * 获得路由Web中的状态页面上的数据
- *
- * @return
- * @throws IOException
- */
- private StringBuffer getWanPacket() throws IOException {
- URL url = new URL(IMailConstant.ROUTE_WEB_STATE);
- InputStream ins = null;
- try {
- ins = url.openConnection().getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(ins));
- String str;
- boolean flag = false;
- StringBuffer wanPacket = new StringBuffer();
- int num = 3;
- while ((str = reader.readLine()) != null && num > 0) {
- if (str.contains("var wanPara = new Array(")) {
- flag = true;
- }
- if (flag) {
- wanPacket.append(str);
- num--;
- }
- }
- return wanPacket;
- }finally{
- if(ins!=null){
- ins.close();
- }
- }
- }
- private String getFirstIp(StringBuffer wanPacket) {
- // 找出数据包中第一个匹配的IP,即为Ip
- Pattern p = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
- Matcher m = p.matcher(wanPacket);
- if (m.find()) {
- return m.group();
- } else {
- return null;
- }
- }
- public static void main(String[] args) {
- try {
- System.out.println(RouteIpUtils.getInstance().getRouteIp());
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- package com.eehome.app.mail;
- public interface IMailConstant {
- /**
- * 发件人地址
- */
- public final static String NOTIFY_EMAIL_MESSAGE_FROM = "wensong1987@126.com";
- /**
- * 提醒邮件标题前缀
- */
- public final static String NOTIFY_EMAIL_MESSAGE_PRE_TITLE = "通知:服务器IP提醒————";
- /**
- * 路由用户名
- */
- public final static String ROUTE_USER = "admin";
- /**
- * 路由密码
- */
- public final static String ROUTE_PWD = "huang";
- /**
- * 路由Web记录状态的页面,里面包含了Wan口ip
- */
- public final static String ROUTE_WEB_STATE = "http://192.168.1.1:83/userRpm/StatusRpm.htm?Connect=连 接&wan=1";
- /**
- * 轮询时间 10分钟
- */
- public final static long POLLING_TIME = 10 * 60 * 1000;
- /**
- * email文件地址
- */
- public final static String EMAIL_FILE_PATH = "/root/mail/mail.txt";
- /**
- * log4j存放地址
- */
- public final static String LOG4J_FILE_PATH = "/root/mail/log/log4j.properties";
- /**
- * 匹配email的正则
- */
- public final static String EMAIL_REG = "[A-Za-z0-9](?:[0-9a-zA-Z_]?\\.?){4,24}@[0-9a-zA-Z_-]{1,59}\\.(?:[0-9a-zA-Z]\\.?[0-9a-zA-Z]?){2,3}";
- }
- package com.eehome.app.mail.model;
- import java.net.Authenticator;
- import java.net.PasswordAuthentication;
- import com.eehome.app.mail.IMailConstant;
- public class RouterPassAuth extends Authenticator {
- @Override
- public PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(IMailConstant.ROUTE_USER,
- IMailConstant.ROUTE_PWD.toCharArray());
- }
- }
考虑到路由IP是动态IP,过一段时间就会变化,我给程序设计了一个轮询机制来检测IP,变化,用一个调度任务来定时获取IP,进行比较,再决定是否发送邮件。
- package com.eehome.app.mail.task;
- import java.io.IOException;
- import java.util.Arrays;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.log4j.PropertyConfigurator;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.mail.javamail.JavaMailSender;
- import com.eehome.app.mail.IMailConstant;
- import com.eehome.app.mail.model.IpNotifyMessage;
- import com.eehome.app.mail.utils.RouteIpUtils;
- /**
- * 邮件提醒任务
- * @author wensong
- * 2010-9-5 下午11:12:17
- */
- public class NotifyEmailSendTask implements Runnable {
- private String[] toMails;
- private Log logger = LogFactory.getLog(this.getClass());
- private static String ip = "192.168.1.110";
- static {
- PropertyConfigurator.configure(IMailConstant.LOG4J_FILE_PATH);
- }
- private static BeanFactory factory = new ClassPathXmlApplicationContext(
- "application-context.xml");
- public NotifyEmailSendTask(String[] toMails) {
- this.toMails = toMails;
- }
- public void run() {
- String routerIp = null;
- try {
- routerIp = RouteIpUtils.getInstance().getRouteIp();
- } catch (IOException e1) {
- logger.warn("连接路由中断,或者路由连接异常:" + e1);
- }
- try {
- if (routerIp != null&&!routerIp.equals("0.0.0.0")) {
- if (!routerIp.equals(ip)) {
- if (!ip.equals("192.168.1.110"))
- logger.info("路由IP发生变化,执行发送邮件任务");
- StringBuffer context = new StringBuffer().append(
- "今日Host:\n").append("eehome.com ")
- .append(routerIp);
- if (!ip.equals("192.168.1.110")) {
- context = new StringBuffer().append("Host变化如下:\n")
- .append("eehome.com ").append(routerIp);
- }
- // 构造邮件消息对象
- IpNotifyMessage message = new IpNotifyMessage(toMails,
- context.toString());
- // 发邮件
- JavaMailSender mailSender = (JavaMailSender) factory
- .getBean("javaMailSender");
- logger.info("发送邮件,发送邮箱为:" + Arrays.toString(toMails));
- mailSender.send(message);
- ip = routerIp;
- } else {
- logger.debug("上次记录的IP为:" + ip + ", 最新路由IP为:" + routerIp
- + " 轮询结果将不发送邮件");
- }
- }
- } catch (Exception e) {
- logger.warn("发送邮件异常:" + e);
- }
- }
- }
- package com.eehome.app.mail.task;
- import java.util.concurrent.TimeUnit;
- import com.eehome.app.mail.IMailConstant;
- import com.eehome.app.mail.utils.EmailsProvider;
- import com.eehome.core.task.EeHomeScheduledExecutor;
- /**
- * 邮件任务调度,采用轮询的方式来检查路由IP是否发生改变,如果改变发送邮件
- *
- * @author wensong 2010-9-4 下午03:34:58
- */
- public class IpNotifyEmailSchedule {
- public static void main(String[] args) {
- String[] mails = EmailsProvider.getInstance().getEmailArrays();
- EeHomeScheduledExecutor.getScheduledExecutor().scheduleWithFixedDelay(
- new NotifyEmailSendTask(mails), 0, IMailConstant.POLLING_TIME,
- TimeUnit.MILLISECONDS);
- }
- }
- package com.eehome.app.mail.model;
- import java.util.Date;
- import org.springframework.mail.SimpleMailMessage;
- import com.eehome.app.mail.IMailConstant;
- import com.eehome.app.mail.utils.DateUtils;
- public class IpNotifyMessage extends SimpleMailMessage {
- private static final long serialVersionUID = -3236307360187426650L;
- public IpNotifyMessage(String toMail, String toText) {
- // 设置邮件标题:提醒邮件标题前缀+当前时间
- setSubject(IMailConstant.NOTIFY_EMAIL_MESSAGE_PRE_TITLE
- + DateUtils.getTimeNow());
- setFrom(IMailConstant.NOTIFY_EMAIL_MESSAGE_FROM);
- setSentDate(new Date());
- setTo(toMail);
- setText(toText);
- }
- public IpNotifyMessage(String[] toMails,String toText){
- // 设置邮件标题:提醒邮件标题前缀+当前时间
- setSubject(IMailConstant.NOTIFY_EMAIL_MESSAGE_PRE_TITLE
- + DateUtils.getTimeNow());
- setFrom(IMailConstant.NOTIFY_EMAIL_MESSAGE_FROM);
- setSentDate(new Date());
- setTo(toMails);
- setText(toText);
- }
- }
- package com.eehome.app.mail.exception;
- public class FileIsNotExistException extends Exception {
- /**
- * 文件不存在异常
- */
- private static final long serialVersionUID = -2545287258814097123L;
- public FileIsNotExistException() {
- super();
- }
- public FileIsNotExistException(String message, Throwable cause) {
- super(message, cause);
- }
- public FileIsNotExistException(String message) {
- super(message);
- }
- public FileIsNotExistException(Throwable cause) {
- super(cause);
- }
- }
- package com.eehome.app.mail.utils;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.log4j.PropertyConfigurator;
- import com.eehome.app.mail.IMailConstant;
- public class EmailsProvider {
- private final static EmailsProvider provider = new EmailsProvider();
- private Log logger = LogFactory.getLog(this.getClass());
- static {
- PropertyConfigurator.configure(IMailConstant.LOG4J_FILE_PATH);
- }
- private EmailsProvider() {
- }
- public static EmailsProvider getInstance() {
- return provider;
- }
- /**
- * 获得Email数组
- *
- * @return
- */
- public String[] getEmailArrays() {
- StringBuilder sb = getEmailStrBuilder();
- if (sb != null) {
- List<String> mailArrays = getEmails(sb);
- return (String[]) mailArrays.toArray(new String[mailArrays.size()]);
- } else {
- return null;
- }
- }
- /**
- * 从指定email配置中获取email
- *
- * @return
- */
- private StringBuilder getEmailStrBuilder() {
- File file = new File(IMailConstant.EMAIL_FILE_PATH);
- InputStream ins = null;
- StringBuilder stringBuilder = new StringBuilder();
- try {
- ins = new FileInputStream(file);
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- ins));
- String str;
- while ((str = reader.readLine()) != null) {
- stringBuilder.append(str).append(",");
- }
- return stringBuilder;
- } catch (FileNotFoundException e) {
- logger.info(file.getPath() + "文件不存在");
- return null;
- } catch (IOException e) {
- logger.info("文件操作异常:" + e);
- return null;
- } finally {
- try {
- ins.close();
- } catch (IOException e) {
- logger.info("文件关闭异常:" + e);
- return null;
- }
- }
- }
- /**
- * 通过正则匹配字符
- * @param stringBuilder
- * @return
- */
- private List<String> getEmails(StringBuilder stringBuilder) {
- List<String> mails = new ArrayList<String>();
- // 创建正则表达式
- Pattern p = Pattern.compile(IMailConstant.EMAIL_REG);
- Matcher m = p.matcher(stringBuilder);
- if (logger.isDebugEnabled()) {
- logger.debug("文件读取的字符串stringBuilder:" + stringBuilder);
- }
- // 找到匹配的字符串
- while (m.find()) {
- mails.add(m.group());
- }
- return mails;
- }
- }
- package com.eehome.app.mail.utils;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class DateUtils {
- public static final SimpleDateFormat sdf = new SimpleDateFormat(
- "yyyyMMddHHmmss");
- /**
- * 获得当前时间组成的字符串,格式为yyyyMMddHHmmss
- * @return
- */
- public static String getTimeNow() {
- return sdf.format(new Date());
- }
- }
- package com.eehome.app.mail.exception;
- public class FileIsNotExistException extends Exception {
- /**
- * 文件不存在异常
- */
- private static final long serialVersionUID = -2545287258814097123L;
- public FileIsNotExistException() {
- super();
- }
- public FileIsNotExistException(String message, Throwable cause) {
- super(message, cause);
- }
- public FileIsNotExistException(String message) {
- super(message);
- }
- public FileIsNotExistException(Throwable cause) {
- super(cause);
- }
- }
接着为了写了一个shell脚本,把它作为一个后台执行的脚本,放到rc.local下,让其开机启动,这样IP邮件提醒的程序大功告成,呵呵。
谁有完整的代码 ?共享下 , 交流下 , 谢谢 。