温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

WebSocket中怎么区分不同客户端

发布时间:2021-08-11 14:45:43 来源:亿速云 阅读:248 作者:Leah 栏目:编程语言

这篇文章将为大家详细讲解有关WebSocket中怎么区分不同客户端,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

获取HttpSession值

    当我们在完成用户登录的功能时,用户登录成功,则将当前用户放入HttpSession中,这是一种很常见的做法,这一部分代码如下(框架是SpringMVC,不详细介绍,具体代码请以自己所用框架为准):

if(Objects.equals(userDetail.getUserDetailPassword(), userPassword)){

//如果当前用户登录成功,则将user对象放入httpSession的currentUser
                httpSession.setAttribute("currentUser",user);resoult = "success";}

    那么接下来问题的关键就来了,我们怎么在Server中获取在这里放入HttpSession中的User对象呢,直接获取肯定是不行的,不卖关子,直接放代码。
    注意,结构如图:

WebSocket中怎么区分不同客户端

    新建一个GetHttpSessionConfigurator类,内容如下:

import javax.servlet.http.HttpSession;import javax.websocket.HandshakeResponse;import javax.websocket.server.HandshakeRequest;import javax.websocket.server.ServerEndpointConfig;import javax.websocket.server.ServerEndpointConfig.Configurator;public class GetHttpSessionConfigurator extends Configurator{@Overridepublic void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession=(HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}

    然后在Server里面注解的地方加上一句:

@ServerEndpoint(value="/server/",configurator=GetHttpSessionConfigurator.class)

    此时,我们就已经可以用

@OnOpenpublic void onOpen(Session session, EndpointConfig config){
            HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
            }

    来获取httpSession对象了,然后直接取出currentUser存储的用户对象就可以了。

    但是,在这里我产生了一个问题:原则上来讲我在server获取的httpsession中取出来的用户对象就是现在正和服务端建立连接的对象,因为这种情况的操作肯定是先登录,然后直接建立连接,可是在实际中多用户同时登录时就不一定是这样子了。因为登录是客户端发起的操作,建立连接也是客户端发起的操作,且不说在客户端这两个操作是否是紧密相连,就算是紧密相连,从服务器验证成功(此时已经放入currentUser对象)返回登录结果给客户端到客户端向服务端发起连接这中间因为网络原因也是会消耗一定时间的。那么这时候一件尴尬的事情就发生了:此时,另一个用户也在登录,并且在之前用户两个操作期间完成了登录验证操作,那么第一个用户连接建立之后取出的use对象就不是这个用户的而是第二个用户的,这就乱套了。这种方法相当于是 ,用户A先对服务器说,记住了,我叫A,然后过了一会儿来说,我要建立连接,我是刚刚告诉你名字那个人。那如果B在A离开那会儿也告诉了服务器我叫B,那么服务器就会把A当成B了。
    当前,上面我所说的我没办法去验证,如果我对HttpSession理解错误那就另当别论了。(应该没理解错吧)如果理解有误还请大神指正。
    所以,感觉上来讲还是第二种方法靠谱一点。

@PathParam获取用户对象

    这种方法是在建立连接时把userId放在建立连接的申请之中,这样的话就不会乱掉了:因为用户A登录成功之后我就把用户A的user对象传回去了,然后用户A拿着自己的userId来对客户端说我要建立连接我是A,服务端自然不会搞错。实现方法如下:
    服务端注解地方如下:

@ServerEndpoint(value="/server/{userId}")

    方法参数如下:

@OnOpenpublic void onOpen(@PathParam("userId")String userId,Session session)

    服务端在建立连接请求时路径如下(cp是jsp中的:)

<c:set var="cp" value="${pageContext.request.contextPath}" />

    currentUser就是我们之前登录成功时放入httpSession的值,这个值即便别的用户登录也不会被刷新因为它是被保存在自己的浏览器之中的。

ws = "ws://localhost:8080" + "${cp}" + "/server"+"/${currentUser.userId}";

    这样的话,服务端就获取到了当前建立连接的用户了。

区分不同客户端

    能够获取不同用户userId之后,我们就可以在服务端进行如下操作来区分用户了,具体见注释。(为了突出要点,代码做了精简,仅仅用于示范区分不同的用户)

    public class Server { //存放每个客户端对应的Server对象,可以考虑使用Map来代替,key作为用户标识 private static CopyOnWriteArraySet<Server> server = new CopyOnWriteArraySet<Server>();     //表示与某个用户的连接会话,通过它给客户端发送数据 @SuppressWarnings("unused")     private Session session;     //用户id private String userId;     //用户id和websocket的session绑定的路由表 @SuppressWarnings("rawtypes")     private static Map routeTable = new HashMap<>();     /**
         * 连接建立成功调用的方法
         * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
         */@SuppressWarnings("unchecked")@OnOpenpublic void onOpen(@PathParam("userId")String userIds,Session session){this.session = session;//获取当前登录用户的idthis.userId=userIds;//将用户id和session绑定到路由表//绑定之后就可以在其它地方根据id来获取session,这时两个用户私聊就可以实现了routeTable.put(userId, session);
        }//其它部分代码就不放了

关于WebSocket中怎么区分不同客户端就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI