java获取本地局域网的外网IP

      近日为了满足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 = "[email protected]";

	/**
	 * 提醒邮件标题前缀
	 */
	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 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 getEmails(StringBuilder stringBuilder) {
		List mails = new ArrayList();

		// 创建正则表达式
		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邮件提醒的程序大功告成,呵呵。

 

 

你可能感兴趣的:(Java,log4j,正则表达式,Apache,Web)