最近想写个B/S架构的聊天系统,因为以前做过C/S架构的QQ聊天系统,所以对于Socket通信编程只是一个巩固。对于C/S架构的聊天系统,由于存在客户端Java应用,所以直接在代码中获取客户端的IP,应用的方法为:
String ip = InetAddress.getLocalHost().getHostAddress();
然而对于WEB系统来说,客户端只是一个浏览器,怎么才能获取用户的IP呢,而且又要分内网环境和外网环境两种。
内网环境:
聊天系统用于内网的话,我首先想到了通过JS来实现获取用户的IP,确实也有方法可以支持:

//通过js获得客户端IP,这里获取的IP是本机所有的IP(包括内网和外网) 

 function GetLocalIPAddr(){ 

 var oSetting = null; 

 var ip = null; 

 try{ 

 oSetting = new ActiveXObject("rcbdyctl.Setting"); 

 ip = oSetting.GetIPAddress; 

 if (ip.length == 0){ 

 return "没有连接到Internet"; 

 } 

 oSetting = null; 

 }catch(e){ 

 return ip; 

 } 

 return ip; 

 }


不过此方法只支持IE浏览器,我不得不加了个判断浏览器类别的方法:

//首先判断客户端的浏览器情况 

 $(function(){ 

 if($.browser.msie){ 

 clientIP = GetLocalIPAddr(); 

 $("#showMessage").html("您的IP为:"+dealWith(clientIP)); 

 sendMessageToServlet("busi=connect&connectIP="+dealWith(clientIP)); 

 }else if($.browser.opera){ 

 //alert("这是一个opera浏览器!"); 

 $("#showMessage").html("建议您使用IE浏览器,否则要手动输入IP!"); 

 }else if($.browser.mozilla){ 

 //alert("这是一个mozilla浏览器!"); 

 $("#showMessage").html("建议您使用IE浏览器,否则要手动输入IP!"); 

 }else if($.browser.safa){ 

 //alert("这是一个safa浏览器!"); 

 $("#showMessage").html("建议您使用IE浏览器,否则要手动输入IP!"); 

 } 

 });


怎么才能完整的获取客户端的IP呢?(如果有哪位朋友做过,期望指点一下啊,交个朋友,呵呵)
外网环境:
我们这边在做的网上营业厅系统中有获取用户外网IP的方法,实现方法:

public static String getCurrentIP(HttpServletRequest request){ 

 String result = ""; 

 if (result == null || result.length() == 0 

 || "unknown".equalsIgnoreCase(result)) { 

 result = request.getHeader("x-forwarded-for"); 

 } 

 if (result == null || result.length() == 0 

 || "unknown".equalsIgnoreCase(result)) { 

 result = request.getHeader("X-Forwarded-For"); 

 } 

 if (result == null || result.length() == 0 

 || "unknown".equalsIgnoreCase(result)) { 

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

 } 

 if (result == null || result.length() == 0 

 || "unknown".equalsIgnoreCase(result)) { 

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

 } 

 if (result == null || result.length() == 0 

 || "unknown".equalsIgnoreCase(result)) { 

 result = request.getHeader("HTTP_X_FORWARDED_FOR"); 

 } 

 if (!StringUtils.isEmpty(result)) { 

 if (result.indexOf(".") != -1){ // 没有"."肯定是非IPv4格式 

 Pattern pat = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); 

 Matcher mat = pat.matcher(result); 

 result = null; 

 while (mat.find()) { 

 result = mat.group(0); 

 break; 

 } 

 } 

 else 

 result = null; 

 }


下面是网上广为流传的解释:
在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。
如果使用了反向代理软件,将http://192.168.1.110 :2046/ 的URL反向代理为 http://www.xxx.cn / 的URL时,用request.getRemoteAddr()方法获取的IP地址是:127.0.0.1 或 192.168.1.110,而并不是客户端的真实IP。
经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器 无法直接拿到客户端的IP,服务器 端应用也无法直接通过转发请求的地址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器地址。当我们访问http://www.5555.cn /index.jsp/ 时,其实并不是我们浏览器真正访问到了服务器上的index.jsp文件,而是先由代理服务器去访问http://192.168.1.110 :2046/index.jsp ,代理服务器再将访问到的结果返回给我们的浏览器,因为是代理服务器去访问index.jsp的,所以index.jsp中通过 request.getRemoteAddr()的方法获取的IP实际上是代理服务器的地址,并不是客户端的IP地址。

public String getRemortIP(HttpServletRequest request) { 

 if (request.getHeader("x-forwarded-for") == null) { 

 return request.getRemoteAddr(); 

 } 

 return request.getHeader("x-forwarded-for"); 

 }



可是当我访问http://www.5555.cn /index.jsp/ 时,返回的IP地址始终是unknown,也并不是如上所示的127.0.0.1 或 192.168.1.110了,而我访问http://192.168.1.110 :2046/index.jsp 时,则能返回客户端的真实IP地址,写了个方法去验证。原因出在了Squid上。squid.conf 的配制文件 forwarded_for 项默认是为on,如果 forwarded_for 设成了 off  则:X-Forwarded-For: unknown
于是可得出获得客户端真实IP地址的方法二:

public String getIpAddr(HttpServletRequest request) { 

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

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

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

 } 

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

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

 } 

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

 ip = request.getRemoteAddr(); 

 } 

 return ip; 

 } 


public String getIpAddr(HttpServletRequest request) { 

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

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

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

 } 

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

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

 } 

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

 ip = request.getRemoteAddr(); 

 } 

 return ip; 

 }




可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串Ip值,究竟哪个才是真正的用户端的真实IP呢?
答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100用户真实IP为: 192.168.1.110