import java.io.*;import java.net.InetAddress;import java.util.*;public class ReadIp { static public HashMap ping; // ping 后的结果集 public HashMap getPing() { // 用来得到ping后的结果集 return ping; } // 当前线程的数量, 防止过多线程摧毁电脑 static int threadCount = 0; public ReadIp() { ping = new HashMap(); } public void Ping(String ip) throws Exception { // 最多30个线程 while (threadCount > 30) Thread.sleep(50); threadCount += 1; PingIp p = new PingIp(ip); p.start(); } public void PingAll() throws Exception { // 首先得到本机的IP,得到网段 //InetAddress host = InetAddress.getLocalHost(); //InetAddress host = InetAddress.getByName(null); InetAddress host = InetAddress.getByName("127.0.0.1"); String hostAddress = host.getHostAddress(); int k = 0; k = hostAddress.lastIndexOf("."); String ss = hostAddress.substring(0, k + 1); for (int i = 1; i <= 255; i++) { // 对所有局域网Ip String iip = ss + i; Ping(iip); } // 等着所有Ping结束 while (threadCount > 0) Thread.sleep(50); } public static void main(String[] args) throws Exception { ReadIp ip = new ReadIp(); ip.PingAll(); Set entries = ping.entrySet(); Iterator iter = entries.iterator(); String k; while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String key = (String) entry.getKey(); String value = (String) entry.getValue(); if (value.equals("true")) System.out.println(key + "-->" + value); } } class PingIp extends Thread { public String ip; // IP public PingIp(String ip) { this.ip = ip; } public void run() { try { Process p = Runtime.getRuntime().exec( "ping " + ip + " -w 300 -n 1"); InputStreamReader ir = new InputStreamReader(p.getInputStream()); LineNumberReader input = new LineNumberReader(ir); // 读取结果行 for (int i = 1; i < 7; i++) input.readLine(); String line = input.readLine(); if (line.length() < 17 || line.substring(8, 17).equals("timed out")) ping.put(ip, "false"); else ping.put(ip, "true"); // 线程结束 threadCount -= 1; } catch (IOException e) { } } }}
======-------------------------------------------------------------------------------------------------------------
java获取本地局域网的外网IP
需求:基本目标实现开机将本地的路由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) { ListmailArrays = 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邮件提醒的程序大功告成,呵呵。