WebSocket区分不同客户端方法

简介: WebSocket区分不同客户端方法

1 获取HttpSession值

在使用websocket来制作多人即时聊天工具的时候,难免会遇到一个问题,如何区分不同的客户端。想要解决这个问题就等于是要解决这样一个问题:如何把当前登录用户的userId传给服务端呢?因为不同的客户端代表着不同的用户,做到了获取不同客户端的userId那么自然就把不同的客户端区分开来了。两种可行获取客户端userId的方法。一种是通过在Server取HttpSession中的值获取当前用户,一种是直接在客户端建立连接时附带上用户的值。


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

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

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

注意,结构如图:


新建一个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{
    @Override
    public 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)

此时,我们就已经可以用


@OnOpen
        public 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理解错误那就另当别论了。(应该没理解错吧)如果理解有误还请大神指正。

所以,感觉上来讲还是第二种方法靠谱一点。


2 @PathParam获取用户对象

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

服务端注解地方如下:

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

方法参数如下:

@OnOpen
        public 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}";

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


3 区分不同客户端

能够获取不同用户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")
        @OnOpen
        public void onOpen(@PathParam("userId")String userIds,Session session){
            this.session = session;
            //获取当前登录用户的id
            this.userId=userIds;
            //将用户id和session绑定到路由表
            //绑定之后就可以在其它地方根据id来获取session,这时两个用户私聊就可以实现了
            routeTable.put(userId, session);
        }
        //其它部分代码就不放了
目录
相关文章
|
前端开发 JavaScript API
netty系列之:使用netty搭建websocket客户端
netty系列之:使用netty搭建websocket客户端
|
23天前
|
JavaScript 前端开发 测试技术
前端全栈之路Deno篇(五):如何快速创建 WebSocket 服务端应用 + 客户端应用 - 可能是2025最佳的Websocket全栈实时应用框架
本文介绍了如何使用Deno 2.0快速构建WebSocket全栈应用,包括服务端和客户端的创建。通过一个简单的代码示例,展示了Deno在WebSocket实现中的便捷与强大,无需额外依赖,即可轻松搭建具备基本功能的WebSocket应用。Deno 2.0被认为是最佳的WebSocket全栈应用JS运行时,适合全栈开发者学习和使用。
|
2月前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
238 7
Jmeter实现WebSocket协议的接口测试方法
|
6月前
|
网络协议 JavaScript 前端开发
WebSocket:实现客户端与服务器实时通信的技术
WebSocket:实现客户端与服务器实时通信的技术
|
6月前
|
移动开发 网络协议 JavaScript
web客户端websocket
web客户端websocket
158 1
|
6月前
|
JSON Java API
Java 编程问题:十三、HTTP 客户端和 WebSocket API
Java 编程问题:十三、HTTP 客户端和 WebSocket API
268 0
|
网络协议 Go API
php-websocket hyperf/websocket-server/client 客户端和服务器实时双向数据传输
php-websocket hyperf/websocket-server/client 客户端和服务器实时双向数据传输
345 0
|
移动开发 负载均衡 网络协议
Nginx代理WebSocket方法
Nginx代理WebSocket方法
|
JavaScript
node.js: ws服务端和WebSocket客户端交互示例
node.js: ws服务端和WebSocket客户端交互示例
666 0
使用WebSocket实现服务端和客户端的通信
使用WebSocket实现服务端和客户端的通信
90 0