tomcat8 的 websocket 支持

使用 tomcat8 开发 WebSocket 服务端非常简单,大致有如下两种方式。

1、使用注解方式开发,被 @ServerEndpoint 修饰的 Java 类即可作为 WebSocket 服务端

2、继承 Endpoint 基类实现 WebSocket 服务端

 

开发被 @ServerEndpoint 修饰的类之后,该类中还可以定义如下方法。

被 @OnOpen 修饰的方法:当客户端与该 WebSocket 服务端建立连接时激发该方法

被 @OnClose 修饰的方法:当客户端与该 WebSocket 服务端断开连接时激发该方法

被 @OnMessage 修饰的方法:当 WebSocket 服务端收到客户端消息时激发该方法

被 @OnError 修饰的方法:当客户端与该 WebSocket 服务端连接出现错误时激发该方法。

 

下面将基于 WebSocket 开发一个多人实时聊天的程序,该程序思路很简单 -- 在这个程序中,每个客户所用的浏览器都与服务器建立一个 WebSocket,从而保持实时连接,这样客户端的浏览器可以随时把数据发送到服务器端;当服务器收到任何一个浏览器发送来的消息之后,将该消息依次向每个客户端浏览器发送一遍。

 

按如下步骤开发 WebSocket 服务端程序即可

1、定义 @OnOpen 修饰的方法,每当客户端连接进来时激发该方法,程序使用集合保存所有连接进来的客户端

2、定义 @OnMessage 修饰的方法,每当该服务端收到客户端消息时激发该方法,服务端收到消息之后遍历保存客户端的集合,并将消息逐个发给所有客户端

3、定义 @OnClose 修饰的方法,每当客户端断开与该服务端连接时激发该方法,程序将该客户端从集合中删除。

 

ChatEndpoint.java

package com.baiguiren;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.OnError;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value="/websocket/chat")
public class ChatEndpoint
{
    private static final String GUEST_PREFIX = "访客";
    private static final AtomicInteger connectionIds = new AtomicInteger(0);
    // 定义一个集合,用于保存所有接入的 WebSocket 客户端
    private static final Set clientSet = new CopyOnWriteArraySet<>();
    // 定义一个成员变量,记录 WebSocket 客户端的聊天昵称
    private final String nickname;
    // 定义一个成员变量,记录与 WebSocket 之间的会话
    private Session session;

    public ChatEndpoint()
    {
        nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
    }

    // 当客户端连接进来时自动激发该方法
    @OnOpen
    public void start(Session session)
    {
        this.session = session;
        // 将 WebSocket 客户端会话添加到集合中
        clientSet.add(this);
        String message = String.format("[%s %s]", nickname, "加入了聊天室");
        // 发送消息
        broadcast(message);
    }

    // 当客户端断开连接时自动激发该方法
    @OnClose
    public void end()
    {
        clientSet.remove(this);
        String message = String.format("[%s %s]", nickname, "离开了聊天室!");
        // 发送消息
        broadcast(message);
    }

    // 每当收到客户端消息时自动激发该方法
    @OnMessage
    public void incoming(String message)
    {
        String filteredMessage = String.format("%s: %s", nickname, filter(message));
        // 发送消息
        broadcast(filteredMessage);
    }

    // 当客户端通信出现错误时激发该方法
    @OnError
    public void onError(Throwable t) throws Throwable
    {
        System.out.println("WebSocket 服务端错误" + t);
    }

    // 实现广播消息的工具方法
    private static void broadcast(String msg)
    {
        // 遍历服务器关联的所有客户端
        for (ChatEndpoint client : clientSet)
        {
            try {
                synchronized (client)
                {
                    // 发送消息
                    client.session.getBasicRemote().sendText(msg);
                }
            } catch (IOException e) {
                System.out.println("聊天错误,向客户端" + client + "发送消息出现错误。");
                clientSet.remove(client);
                try {
                    client.session.close();
                } catch (IOException el) {}

                String message = String.format("[%s %s]", client.nickname, "已经被断开了连接");
                broadcast(message);
            }
        }
    }

    // 定义一个工具方法,用于对字符串中的 HTML 字符标签进行转义
    private static String filter(String message)
    {
        if (message == null)
            return null;
        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);

        for (int i = 0; i < content.length; i++)
        {
            // 控制对尖括号等特殊字符转义
            switch (content[i]) {
                case '<':
                    result.append("<");
                    break;
                case '>':
                    result.append(">");
                    break;
                case '&':
                    result.append("&");
                    break;
                case '"':
                    result.append(""");
                    break;
                default:
                    result.append(content[i]);
            }
        }

        return (result.toString());
    }
}

  

以上文件需要导入 javaee-api-7.0.jar

 

需要说明的是,该 CharEndpoint 类并不是真正的 WebSocket 服务端,它只实现了 WebSocket 服务端的核心功能,Tomcat 会调用它的方法作为 WebSocket 服务端。因此,Tomcat 会为每个 WebSocket 客户端创建一个 ChatEndpoint 对象,也就是说,有一个 WebSocket 服务端,程序就有一个 ChatEndpoint 对象。所以上面程序中的 clientSet 集合保存了多个 ChatEndpoint 对象,其中每个 ChatEndpoint 对象对应一个 WebSocket 客户端。

 

chat.html


    
        使用 WebSocket 通信
    
    
        

  

  

 

转载于:https://www.cnblogs.com/eleven24/p/8680714.html

你可能感兴趣的:(tomcat8 的 websocket 支持)