Java Websocket 获取客户端 IP 地址

Java WebSocket IP About 4,868 words

方法一:反射

如果WebSocket前端有负债均衡,则此方法获取到的都是负载均衡机器的IP地址。

public class WebsocketUtil {

    public static InetSocketAddress getRemoteAddress(Session session) {
        if (session == null) {
            return null;
        }
        Async async = session.getAsyncRemote();

        //在Tomcat 8.0.x版本有效
//        InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async,"base#sos#socketWrapper#socket#sc#remoteAddress");
        //在Tomcat 8.5以上版本有效
        InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async,"base#socketWrapper#socket#sc#remoteAddress");
        return addr;
    }

    private static Object getFieldInstance(Object obj, String fieldPath) {
        String fields[] = fieldPath.split("#");
        for (String field : fields) {
            obj = getField(obj, obj.getClass(), field);
            if (obj == null) {
                return null;
            }
        }
        return obj;
    }

    private static Object getField(Object obj, Class<?> clazz, String fieldName) {
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                Field field;
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(obj);
            } catch (Exception ignore) {
            }
        }
        return null;
    }

}

方法二:HttpSession

前一篇文章 讲过WebSocket关联HttpSession,那我们可以在初始化请求时将ServletRequest中的RemoteAddr(即IP地址)存到HttpSession中,然后再在WebSocket握手阶段获取到的HttpSession并放入到WebSocketSessionUserProperties用户属性这个Map中。这样就可以在WebSocket整个生命周期都能获得连接的客户端IP地址。

单点部署情况

@WebListener
public class MyServletListener implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        HttpSession session = request.getSession();
        System.out.println("requestInitialized session = " + session);
        session.setAttribute("ClientIP", request.getRemoteAddr());//把HttpServletRequest中的IP地址放入HttpSession中,关键字可任取,此处为ClientIP
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("requestDestroyed sre = " + sre);
    }

}

public class WebSocketServerConfigurator extends ServerEndpointConfig.Configurator {

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        System.out.println("modifyHandshake");
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        if (httpSession != null) {
            Map<String, Object> userProperties = sec.getUserProperties();
            userProperties.put(HttpSession.class.getName(), httpSession);
        }
    }
}

@ServerEndpoint(value = "/test/ws/{username}", configurator = WebSocketServerConfigurator.class)
public class WebSocketServer {

    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session) {
        HttpSession httpSession = (HttpSession) session.getUserProperties().get(HttpSession.class.getName());
        System.out.println("onOpen#" + httpSession.getAttribute("ClientIP"));

        // 最大超时时间 60 秒
        session.setMaxIdleTimeout(TimeUnit.MINUTES.toMillis(5));
        session.setMaxBinaryMessageBufferSize(8192 * 1024); // 8KB
        session.setMaxTextMessageBufferSize(8192 * 1024); // 字符数
        session.getAsyncRemote().sendText("123");
    }

    // ... 省略了其他事件
}

负载均衡情况

根据负载机器设置的Header,取出相应的IP地址。

@WebListener
public class MyServletListener implements ServletRequestListener {

    public MyServletListener() {
        System.out.println("MyServletListener 构造方法 加载了, thread name#" + Thread.currentThread().getName() + ", thread id#" + Thread.currentThread().getId());
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        HttpSession session = request.getSession();
        System.out.println("requestInitialized session = " + session + ", getRequestURL#" + request.getRequestURL().toString() + ", getRemoteHost#" + request.getRemoteHost() + ", getRemoteAddr#" + request.getRemoteAddr());

        String host = request.getHeader("Host");
        String xRealIP = request.getHeader("X-Real-IP");
        String  xForwardedFor = request.getHeader("X-Forwarded-For");

        System.out.println("host#" + host + ", X-Real-IP#" + xRealIP + ", X-Forwarded-For#" + xForwardedFor);

        session.setAttribute("ClientIP", xForwardedFor);
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("requestDestroyed sre = " + sre);
    }

}

参考

https://stackoverflow.com/questions/22880055/jsr-356-websockets-with-tomcat-how-to-limit-connections-within-single-ip-addre

Views: 9,802 · Posted: 2021-04-22

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓


Today On History
Browsing Refresh