JAVA服务器端获取客户端远程地址

JAVA服务器端获取客户端远程地址,根据IP获取远程地址,各IP地址查询接口比较

标签: IP地址查询 HTTPS 多线程 SocketTimeoutExcepti 远程地址查询 更多

 

一、根据远程请求,获取远程IP

 

  1. /**

  2. * Copyright (c) 2016,sunnybs.

  3. * All Rights Reserved.

  4. *

  5. * Project Name:sunego-commerce-common

  6. * Package Name:com.sunego.commerce.common.http

  7. * File Name:IPUtils.java

  8. * Date:2016年4月28日 上午11:23:53

    扫描二维码关注公众号,回复: 6545312 查看本文章
  9. *

  10. */

  11. package com.sunego.commerce.common.http;

  12.  
  13. import javax.servlet.http.HttpServletRequest;

  14.  
  15. /**

  16. * ClassName: IPUtils <br/>

  17. * Description: IP查询工具 <br/>

  18. * Date: 2016年4月28日 上午11:23:53 <br/>

  19. * <br/>

  20. *

  21. * @author Administrator(邮箱)

  22. *

  23. * 修改记录

  24. * @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>

  25. *

  26. */

  27.  
  28. public class IPUtils {

  29. public static Address address;

  30.  
  31. /**

  32. *

  33. * getRemoteIP:获取远程请求客户端的外网IP <br/>

  34. *

  35. * @param request

  36. * 请求实体对象

  37. * @return ip 外网ip<br/>

  38. */

  39. public static String getRemoteIP(HttpServletRequest request) {

  40. String ip = request.getHeader("x-forwarded-for");

  41. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

  42. ip = request.getHeader("Proxy-Client-IP");

  43. }

  44. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

  45. ip = request.getHeader("WL-Proxy-Client-IP");

  46. }

  47. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

  48. ip = request.getRemoteAddr();

  49. }

  50. return ip;

  51. }

  52.  
  53. /**

  54. *

  55. * getAddresses:根据外网ip,判断该ip所在的地理位置 <br/>

  56. *

  57. * @param ip

  58. * 外网ip

  59. * @return 该ip所在的地理位置 <br/>

  60. */

  61. public static String getAddresses(String ip) {

  62. return Address.getSingleInstance().getAddresses(ip);

  63. }

  64. }

二、根据远程IP,获取远程物理地址

 
  1. /**

  2. * Copyright (c) 2016,sunnybs.

  3. * All Rights Reserved.

  4. *

  5. * Project Name:sunego-commerce-common

  6. * Package Name:com.sunego.commerce.common.http

  7. * File Name:Address.java

  8. * Date:2016年4月28日 上午11:51:05

  9. *

  10. */

  11. package com.sunego.commerce.common.http;

  12.  
  13. import java.util.HashMap;

  14. import java.util.Map;

  15. import java.util.concurrent.ExecutorService;

  16. import java.util.concurrent.Executors;

  17.  
  18. import org.apache.commons.lang3.StringUtils;

  19.  
  20. import com.sunego.commerce.common.json.JsonUtils;

  21. import com.sunego.commerce.common.log.LogUtils;

  22.  
  23. /**

  24. * ClassName: Address <br/>

  25. * Description: TODO <br/>

  26. * Date: 2016年4月28日 上午11:51:05 <br/>

  27. * <br/>

  28. *

  29. * @author Administrator(邮箱)

  30. *

  31. * 修改记录

  32. * @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>

  33. *

  34. */

  35.  
  36. public class Address {

  37.  
  38. /** 多线程公共变量,key=ip,value=address */

  39. static final Map<String, String> ipAddressMap = new HashMap<String, String>();

  40.  
  41. /** 线程池线程数 */

  42. static final Integer threadSize = 3;

  43.  
  44. /** 太平洋ip地址查询接口 */

  45. static final String urlPcOnline = "http://whois.pconline.com.cn/ipJson.jsp?ip={ip}&timeStamp={timeStamp}";

  46. /** 淘宝ip地址查询接口 */

  47. static final String urlTaobao = "http://ip.taobao.com/service/getIpInfo.php?ip={ip}&timeStamp={timeStamp}";

  48. /** 百度ip地址查询接口 */

  49. static final String urlBaidu = "http://opendata.baidu.com/api.php?resource_id=6006&format=json&query={ip}&timeStamp={timeStamp}";

  50.  
  51. /**

  52. * 私有化构造方法

  53. */

  54. private Address() {

  55. };

  56.  
  57. private static Address address;

  58.  
  59. /**

  60. * 单例模式

  61. */

  62. public static Address getSingleInstance() {

  63. if (null == address) {

  64. // 懒加载

  65. synchronized (Address.class) {

  66. if (null == address) {

  67. address = new Address();

  68. }

  69. }

  70. }

  71. return address;

  72. }

  73.  
  74. /**

  75. * 根据远程ip,查询对应的物理地址<br/>

  76. * 只返回所查询到的地址的最后一级,例如address="北京市海淀区西二旗",则返回"西二旗"<br/>

  77. * 使用太平洋、淘宝、百度三个ip地址查询接口,多进程异步查询<br/>

  78. */

  79. public String getAddresses(String ip) {

  80. // 清除上次查询结果

  81. ipAddressMap.remove(ip);

  82. // 创建一个可以执行三个线程的线程池

  83. ExecutorService pool = Executors.newFixedThreadPool(threadSize);

  84. // 记录起始查询时间,超时未查到就返回空

  85. Long begin = System.currentTimeMillis();

  86. // 设置时间戳,防止ip查询接口缓存数据

  87. String timeStamp = String.valueOf(begin);

  88. // 太平洋ip接口查询

  89. pool.execute(new AddressPcOnline(ip, timeStamp));

  90. // 淘宝ip接口查询

  91. pool.execute(new AddressTaobao(ip, timeStamp));

  92. // 百度ip接口查询

  93. pool.execute(new AddressBaidu(ip, timeStamp));

  94. // 开始判断是否查询到结果

  95. while (null == ipAddressMap.get(ip) && System.currentTimeMillis() - begin < 3000) {

  96. // 还未获得地址,且未超时(3秒),就等待(50毫秒)

  97. try {

  98. Thread.sleep(50);

  99. } catch (InterruptedException e) {

  100. // 返回空

  101. return null;

  102. }

  103. }

  104. // 立即关闭所有进程

  105. pool.shutdownNow();

  106. // 返回查询到的结果

  107. return ipAddressMap.get(ip);

  108. }

  109.  
  110. public class AddressPcOnline implements Runnable {

  111. private String ip;

  112. private String timeStamp;

  113. String address;

  114.  
  115. AddressPcOnline(String ip, String timeStamp) {

  116. this.ip = ip;

  117. this.timeStamp = timeStamp;

  118. }

  119.  
  120. @Override

  121. public void run() {

  122. try {

  123. String result = NHttpPool.getString(urlPcOnline.replace("{ip}", ip).replace("{timeStamp}", timeStamp),

  124. NHttpPool.CHARSET_GBK);

  125. result = StringUtils.trim(result);

  126. result = result.substring(34, result.length() - 3);

  127. Map<?, ?> jsonResult = JsonUtils.toObject(result, Map.class);

  128. if (StringUtils.isNotBlank(ipAddressMap.get(ip))) {

  129. return;

  130. }

  131. LogUtils.LOG_BIZ_INFO.info("urlPcOnline | ip=" + ip + " | result=" + result);

  132. address = (String) jsonResult.get("region");

  133. if (StringUtils.isNotEmpty(address)) {

  134. ipAddressMap.put(ip, address);

  135. return;

  136. }

  137. address = (String) jsonResult.get("city");

  138. if (StringUtils.isNotEmpty(address)) {

  139. ipAddressMap.put(ip, address);

  140. return;

  141. }

  142. address = (String) jsonResult.get("pro");

  143. ipAddressMap.put(ip, address);

  144. } catch (Exception e) {

  145. }

  146. }

  147. }

  148.  
  149. public class AddressTaobao implements Runnable {

  150. private String ip;

  151. private String timeStamp;

  152. String address;

  153.  
  154. AddressTaobao(String ip, String timeStamp) {

  155. this.ip = ip;

  156. this.timeStamp = timeStamp;

  157. }

  158.  
  159. @Override

  160. public void run() {

  161. try {

  162. String result = NHttpPool.getString(urlTaobao.replace("{ip}", ip).replace("{timeStamp}", timeStamp),

  163. NHttpPool.CHARSET_GBK);

  164. result = result.substring(17, result.length() - 1);

  165. Map<?, ?> jsonResult = JsonUtils.toObject(result, Map.class);

  166. if (StringUtils.isNotBlank(ipAddressMap.get(ip))) {

  167. return;

  168. }

  169. LogUtils.LOG_BIZ_INFO.info("urlTaobao | ip=" + ip + " | result=" + result);

  170. address = (String) jsonResult.get("county");

  171. if (StringUtils.isNotEmpty(address)) {

  172. ipAddressMap.put(ip, address);

  173. return;

  174. }

  175. address = (String) jsonResult.get("city");

  176. if (StringUtils.isNotEmpty(address)) {

  177. ipAddressMap.put(ip, address);

  178. return;

  179. }

  180. address = (String) jsonResult.get("region");

  181. ipAddressMap.put(ip, address);

  182. } catch (Exception e) {

  183. }

  184. }

  185. }

  186.  
  187. public class AddressBaidu implements Runnable {

  188. private String ip;

  189. private String timeStamp;

  190. String address;

  191.  
  192. AddressBaidu(String ip, String timeStamp) {

  193. this.ip = ip;

  194. this.timeStamp = timeStamp;

  195. }

  196.  
  197. @Override

  198. public void run() {

  199. try {

  200. String result = NHttpPool.getString(urlBaidu.replace("{ip}", ip).replace("{timeStamp}", timeStamp),

  201. NHttpPool.CHARSET_GBK);

  202. result = result.substring(49, result.length() - 2);

  203. Map<?, ?> jsonResult = JsonUtils.toObject(result, Map.class);

  204. if (StringUtils.isNotBlank(ipAddressMap.get(ip))) {

  205. return;

  206. }

  207. LogUtils.LOG_BIZ_INFO.info("urlBaidu | ip=" + ip + " | result=" + result);

  208. address = (String) jsonResult.get("location");

  209. if (address.indexOf(" ") > 0) {

  210. address = address.substring(0, address.indexOf(" "));

  211. }

  212. if (address.indexOf("省") + 1 == address.length()) {

  213. ipAddressMap.put(ip, address);

  214. return;

  215. }

  216. if (address.indexOf("市") + 1 == address.length()) {

  217. address = address.substring(address.indexOf("省") + 1);

  218. ipAddressMap.put(ip, address);

  219. return;

  220. }

  221. address = address.substring(address.indexOf("市") + 1, address.length());

  222. ipAddressMap.put(ip, address);

  223. } catch (Exception e) {

  224. }

  225. }

  226. }

  227. }

三、测试用例

 
  1. /**

  2. * Copyright (c) 2016,sunnybs.

  3. * All Rights Reserved.

  4. *

  5. * Project Name:sunego-commerce-common

  6. * Package Name:com.sunego.commerce.common.price

  7. * File Name:PriceUtilsTest.java

  8. * Date:2016年2月20日 下午2:55:35

  9. *

  10. */

  11. package com.sunego.commerce.common.price;

  12.  
  13. import java.util.ArrayList;

  14. import java.util.List;

  15.  
  16. import org.junit.Test;

  17.  
  18. import com.sunego.commerce.common.http.IPUtils;

  19.  
  20. /**

  21. * ClassName: PriceUtilsTest <br/>

  22. * Description: TODO <br/>

  23. * Date: 2016年2月20日 下午2:55:35 <br/>

  24. * <br/>

  25. *

  26. * @author WSP(邮箱)

  27. *

  28. * 修改记录

  29. * @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>

  30. *

  31. */

  32.  
  33. public class IPUtilsTest {

  34. @Test

  35. public void testIPUtils() {

  36. /**

  37. * 以下接口不可用 <br>

  38. * "http://www.hujuntao.com/api/ip/ip.php";<br>

  39. * "http://fw.qq.com/ipaddress";<br>

  40. * "http://pv.sohu.com/cityjson";// 仅支持js,不接受ip参数<br>

  41. * "http://j.maxmind.com/app/geoip.js";<br>

  42. * "http://www.youdao.com/smartresult-xml/search.s";<br>

  43. * "http://ip.ws.126.net/ipquery";// 仅支持js<br>

  44. * "http://app.hao123.com/ipquery/getcity.php?rtype=2";<br>

  45. * "http://w.1616.net/chaxun/iptolocal.php?ip=";// 太慢<br>

  46. */

  47. List<String> ipList = new ArrayList<String>();

  48. ipList.add("219.137.144.0");// 广东省广州市海珠区

  49. ipList.add("1.85.35.131");// 陕西省西安市 电信

  50. ipList.add("59.108.111.0");// 北京市北京市 方正宽带

  51. ipList.add("59.104.167.0");// 台湾省

  52. ipList.add("61.186.76.165");// 湖南省怀化市 电信

  53. ipList.add("221.202.127.39");// 辽宁省葫芦岛市 联通

  54. ipList.add("114.252.45.210");// 北京市北京市 联通

  55. ipList.add("127.0.0.1");// 未分配或者内网

  56. ipList.add("192.168.10.170");// 未分配或者内网

  57. ipList.add("132.191.25.116:8080");// 辽宁省葫芦岛市

  58.  
  59. for (int i = 0; i < ipList.size(); i++) {

  60. String ip = ipList.get(i);

  61. String addresses = IPUtils.getAddresses(ip);

  62. System.out.println(ip + "==" + addresses);

  63. }

  64. System.err.println("\r\n\r\n***************************\r\n\r\n睡5秒\r\n\r\n***************************\r\n\r\n");

  65. try {

  66. Thread.sleep(5000);

  67. } catch (InterruptedException e) {

  68. e.printStackTrace();

  69. }

  70. for (int j = 63; j < 266; j += 63) {

  71. for (int k = 0; k < 266; k += 19) {

  72. for (int m = 0; m < 266; m += 13) {

  73. String ip = "60." + j + "." + k + "." + m;

  74. String address1 = IPUtils.getAddresses(ip);

  75. System.out.println(ip + "==" + address1);

  76. }

  77. }

  78. }

  79. }

  80.  
  81. }


代码整完了,问题也解决了……

说明一下,

我最开始获取客户端地址,用的是在前端页面引入“http://ip.ws.126.net/ipquery”接口,

但此接口只支持js,无法写到Java后台去,

项目从http转https后该接口边便失效,又找不到https协议的ip查询接口,

因此只能在后台获取远程ip(LSB的话记得ip转换),便开始在后台使用淘宝的ip地址查询接口,

可是高频率访问时淘宝ip地址查询接口总是SocketTimeout,经过各种Httpclient优化无效,后来发现加上时间戳去缓存可以改善连接超时,

就这样用了一段时间后,频繁访问时还是会报SocketTimeoutException,

因此又调研了这许多接口,最终确定了三个比较高效、精确、稳定的接口,做成了多线程的方式随机访问。

猜你喜欢

转载自blog.csdn.net/zxl2016/article/details/90369013