WebSocket实现消息推送

引言

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

        WebSocket实现消息推送_第1张图片

一、Socket简介

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

                                     

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

客户端代码 index.jsp:

<%@ page language="java" pageEncoding="UTF-8" %>



    Java后端WebSocket的Tomcat实现


    Welcome


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

服务端代码:

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 webSocketSet = new CopyOnWriteArraySet();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    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();

        }
    }
}

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

WebSocket实现消息推送_第2张图片

 

这样实现了基本的交互,但是我们在使用中通常,需要在在另一个服务端生产消息,然后推送给前端页面,下面看一下生产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

 
            javax.websocket
            javax.websocket-api
            1.1
            provided
        

生产消息代码:

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方法我们会遇到下面错误:

WebSocket实现消息推送_第3张图片

如果我们将同样的代码部署在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

 

你可能感兴趣的:(@JAVA学习)