websocket作为服务端收发信息的demo

简介: websocket作为服务端收发信息的demo

websocket的使用可以使前后端的数据之间进行实时通讯。普通的web程序,由客户端发出请求,由服务端接收请求,进行处理并将结果返回客户端的这么一个流程。可是如果服务端的数据变化频率比较快,客户端要想要比较实时的获得最新的服务端数据,可能需要不断的发送请求,而websoceket进行一次握手之后,浏览器和服务器之间就会建立一条通道,就可以随时进行数据传输。


websocket里面使用@Autowired注入bseries和bean的时候可能会取不到,原因是spring管理的都是单例(singleton),和 websocket (多对象)相冲突。项目启动时初始化,会初始化 websocket (非用户连接的),spring 同时会为其注入 service,该对象的 service 不是 null,被成功注入。但是,由于 spring 默认管理的是单例,所以只会注入一次 service。当新用户进入聊天时,系统又会创建一个新的 websocket 对象,这时矛盾出现了:spring 管理的都是单例,不会给第二个 websocket 对象注入 service,所以导致只要是用户连接创建的 websocket 对象,都不能再注入了。


下面是websocket作为服务端的一个demo:

@ServerEndpoint("/webSocket/{sid}")
@Slf4j
@Component
public class WebSocketServer {
  /**
   * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
   */
  private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
  /**
   * 与某个客户端的连接会话,需要通过它来给客户端发送数据
   */
  private Session session;
  /**
   * 接收sid
   */
  private String sid="";
  //存储session的map
  private static Map<String,Object> dataMap = new HashMap<String,Object>();
  /**
   * 连接建立成功调用的方法
   * */
  @OnOpen
  public void onOpen(Session session,@PathParam("sid") String sid) {
    this.session = session;
    //将session存起来
    dataMap.put(sid,session);
    //如果存在就先删除一个,防止重复推送消息
    for (WebSocketServer webSocket:webSocketSet) {
      if (webSocket.sid.equals(sid)) {
        webSocketSet.remove(webSocket);
      }
    }
    webSocketSet.add(this);
    this.sid=sid;
    log.info("连接已建立");
  }
  /**
   * 连接关闭调用的方法
   */
  @OnClose
  public void onClose() {
    webSocketSet.remove(this);
    log.info("连接已关闭");
  }
  /**
   * 收到客户端消息后调用的方法
   * @param message 客户端发送过来的消息*/
  @OnMessage
  public void onMessage(String message, Session session) {
    log.info("收到来"+sid+"的信息:"+message);
    String sid = getSid(session);
    if (sid == null) {
      return;
    }
    //群发消息
    for (WebSocketServer item : webSocketSet) {
      try {
        item.sendMessage(message,sid);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  public String getSid(Session session) {
    String sid = null;
    for (String key:dataMap.keySet()) {
      Session cursession = (Session) dataMap.get(key);
      if (cursession == session) {
        sid = key;
        break;
      }
    }
    return sid;
  }
  @OnError
  public void onError(Session session, Throwable error) {
    log.error("发生错误");
    error.printStackTrace();
  }
  /**
   * 实现服务器主动推送
   */
  public void sendMessage(String message, String sid) throws IOException {
    Session session = (Session) dataMap.get(sid);
    session.getBasicRemote().sendText(message);
  }
  /**
   * 群发自定义消息
   * */
  public static void sendInfo(SocketMsg socketMsg, @PathParam("sid") String sid) throws IOException {
    String message = JSONObject.toJSONString(socketMsg);
    log.info("推送消息到"+sid+",推送内容:"+message);
    for (WebSocketServer item : webSocketSet) {
      try {
        //这里可以设定只推送给这个sid的,为null则全部推送
        if(sid==null) {
          item.sendMessage(message,sid);
        }else if(item.sid.equals(sid)){
          item.sendMessage(message,sid);
        }
      } catch (IOException ignored) { }
    }
  }
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    WebSocketServer that = (WebSocketServer) o;
    return Objects.equals(session, that.session) &&
        Objects.equals(sid, that.sid);
  }
  @Override
  public int hashCode() {
    return Objects.hash(session, sid);
  }
}

这是websocket作为服务端的其中一种写法,在连接websocket的时候,传入了一个区分用户的ID,并把用户ID存在session中,这里的session代表的是一个websocket连接,这样在服务端向前端返回数据的时候就会知道是给谁发送的信息了。

websocket的传输信息的数据类型好像只有字符串,而且在默认情况下,会有大小的一个限制。解决方式后面补上。


自己测试的时候,可以使用

websocket在线测试


来进行收发信息的测试,注意连接的地址是以 ws:// 开头的,以上面的后端代码为例,@ServerEndpoint("/webSocket/{sid}")注解需要的连接格式为:

ws://127.0.0.1:8080/webSocket/123


连接成功以后就可以收发信息了。


目录
相关文章
|
7月前
|
前端开发 Java 程序员
Spring Boot+Netty+Websocket实现后台向前端推送信息
学过 Netty 的都知道,Netty 对 NIO 进行了很好的封装,简单的 API,庞大的开源社区。深受广大程序员喜爱。基于此本文分享一下基础的 netty 使用。实战制作一个 Netty + websocket 的消息推送小栗子。
|
4月前
|
Dart 小程序 前端开发
WebSocket 解析与应用(包含web前端、服务端、小程序、dart/flutter中的用法)
WebSocket 解析与应用(包含web前端、服务端、小程序、dart/flutter中的用法)
222 0
|
4月前
|
测试技术
Netty4 websocket 开启服务端并设置IP和端口号
Netty4 websocket 开启服务端并设置IP和端口号
68 0
|
4月前
ModelScope-FunASR的WebSocket连接中断后,服务端不会自动关闭连接
ModelScope-FunASR的WebSocket连接中断后,服务端不会自动关闭连接【1月更文挑战第11天】【1月更文挑战第55篇】
60 2
|
4月前
|
网络协议 Java 应用服务中间件
如何将本地websocket发布至公网并实现远程访问服务端
如何将本地websocket发布至公网并实现远程访问服务端
70 0
|
消息中间件 前端开发 JavaScript
Spring Boot+Netty+Websocket实现后台向前端推送信息
Spring Boot+Netty+Websocket实现后台向前端推送信息
|
8月前
使用WebSocket实现服务端和客户端的通信
使用WebSocket实现服务端和客户端的通信
60 0
|
前端开发 JavaScript Java
使用Springboot 2.7+Websocket+js实现服务端消息实时推送
使用Springboot 2.7+Websocket+js实现服务端消息实时推送
使用Springboot 2.7+Websocket+js实现服务端消息实时推送
|
10月前
|
JSON 关系型数据库 MySQL
php使用webSocket实现Echarts长连接自动刷新的解决方案(2):后端服务端代码返回json数据
php使用webSocket实现Echarts长连接自动刷新的解决方案(2):后端服务端代码返回json数据
113 0
|
10月前
|
JavaScript 前端开发 Java
java springboot websocket vue 实现发送信息
java springboot websocket vue 实现发送信息