在Java7与Tomcat8环境下使用WebSocket实现聊天的示例

在Java7与Tomcat8环境下使用WebSocket实现聊天的示例,第1张

在Java7与Tomcat8环境下使用WebSocket实现聊天的示例

案例在apache-tomcat-8.0.15和jdk1.8.0_25中开发运行。不过标题是Java7,不影响。代码中没有与jdk1.8.x相关的代码。另外,之所以解释软件版本,一是为了保证案例能够有一个清晰的实现背景,二是tomcat7.x的websocket实现与Tomcat8.x有很大的不同。


在JavaEE规范集中,我们主要看JavaAPIforWebSocket(JSR356)。Websocket-api为Java实现Websocket提供了一个接口。最重要的类和注释如下:

上图说明:

1.最上面的四个注释,OnClose、OnError、OnOpen和OnMessage,用于标记POJO处理WebSocket请求所使用的方法;

2.Endpoint和EndpointConfig分别定义了端点和端点相关配置的接口方法;

3.ClientEndpoint和ServerEndpoint分别定义了客户端和服务器端的接口方法;

4.解码器和编码器分别是解码和编码的接口方法定义;

5.Session是与端点相关的WebSocket会话接口方法的定义。

除此之外,还有其他接口。作为对Javawebsocketapi的初步了解,这里只列出最需要的。


Tomcat8.x提供了JavaEE7的标准实现,由WebSocket1.1规范实现。用它开发的依赖环境是Tomcat8.xJDK7。Tomcat8.x提供服务器端实现,客户端实现需要java_websocket等其他实现。

Tomcat8.x对WebSocket的实现感觉非常清楚。由于WebSocket相关的注释和会话都是在API中定义的,所以在Tomcat8.x实现中自然会有相应的处理和实现。下图是一个简单的关系描述。


上图说明:

  • Tomcat的WsSession类实现了JavaWebSocketAPI中的Session接口。

  • PojoEndpointBase及其子类处理与端点相关的类或注释。

    EndpointConfig,Endpoint都与Session的实现类有依赖关系。


    通过了解JavaWebsocketAPI和Tomcat8.x的实现,认为使用JavaWebsocket需要熟悉关键类或接口,如Endpoint、EndpointConfig、Client和Server、编码器和解码器、Session和MessageHandler。


    上面介绍了Tomcat8.x对JavaWebsocket的实现。有关WebSocket规范的信息,请参考:

    RFC6455:http://tools.ietf.org/html/rfc6455

    WebSocket的服务器端实现:https://Java.net/projects/websocket-Spec/Pages/WebSocketapis


    下面的代码示例展示了基于WebSocket的实时聊天。

    1.服务器端实现

    package t8j8.examples; import java.io.IOException; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; @ServerEndpoint(value = "/ws/chat/{nickName}") public class Chat {     /**      * 连接对象集合      */     private static final Set<Chat> connections = new CopyOnWriteArraySet<Chat>();     private String nickName;     /**      * WebSocket Session      */     private Session session;     public Chat() {     }     /**      * 打开连接      *       * @param session      * @param nickName      */     @OnOpen     public void onOpen(Session session,             @PathParam(value = "nickName") String nickName) {         this.session = session;         this.nickName = nickName;         connections.add(this);         String message = String.format("System> %s %s", this.nickName,                 " has joined.");         Chat.broadCast(message);     }     /**      * 关闭连接      */     @OnClose     public void onClose() {         connections.remove(this);         String message = String.format("System> %s, %s", this.nickName,                 " has disconnection.");         Chat.broadCast(message);     }     /**      * 接收信息      *       * @param message      * @param nickName      */     @OnMessage     public void onMessage(String message,             @PathParam(value = "nickName") String nickName) {         Chat.broadCast(nickName + ">" + message);     }     /**      * 错误信息响应      *       * @param throwable      */     @OnError     public void onError(Throwable throwable) {         System.out.println(throwable.getMessage());     }     /**      * 发送或广播信息      *       * @param message      */     private static void broadCast(String message) {         for (Chat chat : connections) {             try {                 synchronized (chat) {                     chat.session.getBasicRemote().sendText(message);                 }             } catch (IOException e) {                 connections.remove(chat);                 try {                     chat.session.close();                 } catch (IOException e1) {                 }                 Chat.broadCast(String.format("System> %s %s", chat.nickName,                         " has bean disconnection."));             }         }     } }

    解释:

    代码中ServerEndpoint批注的value值中有一个昵称的参数占位符,称为path参数,path参数可以通过方法参数批注(@PathParam)设置和获取;

    在Endpoint批注的类中,OnClose、OnOpen、OnErroronerror批注只能有一个方法,OnMessage批注可以有多个方法。这很容易理解,因为WebSocket可能会处理文本、二进制、textStream等信息。


    2.客户端实现

    如果使用Maven,可以添加java_websocketjar的依赖。

    <dependency>             <groupId>org.java-websocket</groupId>             <artifactId>Java-WebSocket</artifactId>             <version>1.3.0</version>             <scope>runtime</scope>         </dependency>


    如果开发Web客户端,可以选择支持WebSocket的浏览器,使用HTML5技术。


    下面是使用java_websocket实现客户端的代码:

    package t8j8.examples.client; import java.net.URI; import java.net.URISyntaxException; import java.util.Scanner; import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft_17; import org.java_websocket.handshake.ServerHandshake; public class TestTocatWebSocket {     public static void main(String[] args) throws URISyntaxException {         String url = "ws://localhost:8080/t8j8/ws/chat/" + args[0];         WebSocketClient wc = new WebSocketClient(new URI(url), new Draft_17()) {             @Override             public void onOpen(ServerHandshake handshakedata) {                 System.out.println(handshakedata.getHttpStatusMessage());             }             @Override             public void onMessage(String message) {                 System.out.println(message);             }             @Override             public void onError(Exception ex) {             }             @Override             public void onClose(int code, String reason, boolean remote) {             }         };         wc.connect();         while (true) {             Scanner scanner = new Scanner(System.in);             String message = scanner.nextLine();             if (message.equals("q")) {                 wc.close();                 break;             }             scanner.close();             wc.send(message);         }     } }

    描述:

    客户端要说明的是创建新的Draft_17()对象,通过类名就可以知道Draft的意思。由于Websocket标准发布时间不长,之前的实现都是基于草案的,这里的Draft_17对应的WebSocket版本是["sec-WebSocket-version","13"]。可惜java_websocket包很久没有更新了,名字被误解了。


    开始聊天

    部署服务器端程序,启动客户端程序(需要添加昵称参数)。

    下面分别是汤姆和杰克的聊天截图。

    至此,使用Tomcat8和JDK7的基于WebSocket的聊天示例结束。

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/zz/784143.html

    (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    上一篇 2022-05-04
    下一篇 2022-05-04

    发表评论

    登录后才能评论

    评论列表(0条)

    保存