WebSocket实现消息推送

简介: WebSocket实现消息推送

引言


最近项目中需要实现消息推送需求,首先想到就是用webscket来实现IM,之前了解过这个东西,但是很久没有用了,所以需要来弄个demo热热身,这样在项目中使用的时候,会更靠谱些。先来看一下最后的效果:


20181026224518350.jpg



一、Socket简介


Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。Socket的英文原义是“孔”或“插座”,作为UNIX的进程通信机制。Socket可以实现应用程序间网络通信。


其余的一些想它为什么会出现,以及他和我们常用的http协议之间的区别等等,自己百度吧,网上有很多资料,这里我们就不浪费时间了,直接撸代码:


客户端代码 index.jsp:


<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>Java后端WebSocket的Tomcat实现</title>
</head>
<body>
    Welcome<br/><input id="text" type="text"/>
    <button onclick="send()">发送消息</button>
    <hr/>
    <button onclick="closeWebSocket()">关闭WebSocket连接</button>
    <hr/>
    <div id="message"></div>
</body>
<script type="text/javascript">
    var websocket = null;
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://localhost:8080/websocket");
    }
    else {
        alert('当前浏览器 Not support websocket')
    }
    //连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("WebSocket连接发生错误");
    };
    //连接成功建立的回调方法
    websocket.onopen = function () {
        setMessageInnerHTML("WebSocket连接成功");
    }
    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
    }
    //连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("WebSocket连接关闭");
    }
    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        closeWebSocket();
    }
    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }
    //关闭WebSocket连接
    function closeWebSocket() {
        websocket.close();
    }
    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>


上面代码实现了浏览器和后端的链接和通信、;


服务端代码:


package me.gacl.websocket;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint("/websocket")
public class WebSocketTest {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
    private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    /**
     * 连接建立成功调用的方法
     *
     * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
    }
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
        //群发消息
        for (WebSocketTest item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }
    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }
    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
     *
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    public static synchronized void addOnlineCount() {
        WebSocketTest.onlineCount++;
    }
    public static synchronized void subOnlineCount() {
        WebSocketTest.onlineCount--;
    }
    public void sends() {
        MyClient client = new MyClient();
        String uri = "ws://localhost:8080/websocket";
        client.start(uri);
        int num = 0;
        try {
            while (true) {
                Thread.sleep(3 * 1000);
                num++;
                client.sendMessage("消息测试" + num);
                client.closeSocket();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

有这两部分就可以实现消息的发送和接受了,也就是我们发送消息,多个客户端都可以接收到信息


2018102622090261.png


这样实现了基本的交互,但是我们在使用中通常,需要在在另一个服务端生产消息,然后推送给前端页面,下面看一下生产du端代码


client代码:

package com.zqf.common.websockt;
import java.io.IOException;
import java.net.URI;
import javax.websocket.*;
@ClientEndpoint
public class MyClient {
    private Session session;
    @OnOpen
    public void onOpen(Session session) throws IOException {
        this.session = session;
    }
    @OnMessage
    public void onMessage(String message) {
    }
    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }
    /**
     * 连接关闭调用的方法
     * @throws Exception 
     */
    @OnClose
    public void onClose() throws Exception{
    }
    /**
     * 关闭链接方法
     * @throws IOException
     */
    public void closeSocket() throws IOException{
        this.session.close();
    }
    /**
     * 发送消息方法。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException{
        this.session.getBasicRemote().sendText(message);
    }
    //启动客户端并建立链接
    public void start(String uri) {
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        try {
            this.session = container.connectToServer(MyClient.class, URI.create(uri));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上面代码需要我们引入jar

 <dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.1</version>
            <scope>provided</scope>
        </dependency>

生产消息代码:

public void websocket(){
    MyClient client = new MyClient();
    String uri = "ws://localhost:8080/websocket";
    client.start(uri);
    int num=0;
    while (true) {
      try {
        Thread.sleep(2*1000);
        num++;
        client.sendMessage("消息测试" + num);
        System.out.println(num);
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }


注意:这里我们需要注意一个坑,就是我们在生产消息的时候,可能我们都习惯直接在main方法中来模拟消息的生产,如果用main方法我们会遇到下面错误:


20181026221643859.png


如果我们将同样的代码部署在tomcat上就没有问题,查询了一些资料,是因为tomcat中有一个支持websocket的jar,需要导入tomcat bin 目录下的tomcat-juli.jar 到Bootstrap 类加载器对应的实体中,看下面文章


http://blog.sina.com.cn/s/blog_145f07e7b0102xa7a.html


小编是直接将生产的代码部署到了tomcat上,毕竟也是非常简单的,在这个阶段先实现功能,不能被这个小问题阻挡,最后顺利实现开始的效果:


源代码已经放在github上:https://github.com/zhenghaoxiao/java-web-socket


目录
相关文章
|
16天前
|
负载均衡 网络协议 C#
C#实现WebSocket实时消息推送技术详解
C#实现WebSocket实时消息推送技术详解
23 1
|
5月前
|
监控 JavaScript API
局域网监控软件的实时通知系统:利用Node.js和WebSocket实现即时消息推送
本文介绍了如何使用Node.js和WebSocket构建局域网监控软件的实时通知系统。实时通知对于网络安全和家庭监控至关重要,能即时发送监控数据变化的通知,提高响应速度。通过Node.js创建WebSocket服务器,当数据变化时,监控软件发送消息至服务器,服务器随即推送给客户端。此外,还展示了如何利用Node.js编写API,自动将监控数据提交到网站,便于用户查看历史记录,从而提升监控体验。
171 3
|
2月前
|
人工智能 数据库连接 Go
Golang 搭建 WebSocket 应用(五) - 消息推送日志
Golang 搭建 WebSocket 应用(五) - 消息推送日志
28 1
|
2月前
|
人工智能 JSON 安全
Golang 搭建 WebSocket 应用(三) - 实现一个消息推送中心
Golang 搭建 WebSocket 应用(三) - 实现一个消息推送中心
77 0
|
2月前
|
JavaScript 前端开发 网络协议
WebSocket在Java Spring Boot+Vue框架中实现消息推送功能
在现代Web应用中,实时消息提醒是一项非常重要的功能,能够极大地提升用户体验。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为实现实时消息提醒提供了高效且低延迟的解决方案。本文将详细介绍如何在Java Spring Boot后端和Vue前端框架中利用WebSocket实现消息提醒功能。
113 0
|
3月前
|
前端开发 JavaScript Java
实现基于WebSocket的实时消息推送
实现基于WebSocket的实时消息推送
|
11月前
|
前端开发 Java 测试技术
SpringBoot整合WebSocket实现定时任务消息推送
SpringBoot整合WebSocket实现定时任务消息推送
288 0
|
5月前
|
Java
SpringBoot:第七篇 websocket(消息推送)
SpringBoot:第七篇 websocket(消息推送)
88 0
|
JavaScript 网络协议 安全
基于若依(SpringBoot前后分离版-vue)的WebSocket消息推送实现
基于若依(SpringBoot前后分离版-vue)的WebSocket消息推送实现
4531 1
|
NoSQL Go Redis
Go WebSocket + Redis 实现轻量级的订阅和实时消息推送
Go WebSocket + Redis 实现轻量级的订阅和实时消息推送