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

简介:
+关注继续查看

文中案例在apache-tomcat-8.0.15和jdk1.8.0_25环境下开发,运行。不过标题上是Java7,并不造成影响,代码中没有涉及任何与jdk1.8.x相关的代码。另外之所以要讲清软件版本,一是为了保证案例能够有个明确的实现背景,二是websocket实现tomcat7.x与tomcat8.x有很大差异。

   

  在JavaEE规范集中我们这里主要看Java API for WebSocket(JSR 356)。Websocket-api提供了Java实现Websocket的接口,其中最重要的几个类和注解如下图:

  wKiom1R71HfSnxu9AATraxMbUG0847.jpg

上图解释:

1.最上面4个注解OnClose,OnError, OnOpen, OnMessage用来标注一个POJO用来处理WebSocket请求的方法;

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

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

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

5.Session是与Endpoint相关的WebSocket Session接口方法定义。

另外还有其它接口,这里作为初步了解Java websocket api仅列出最有必要的一些。


   Tomcat8.x提供了JavaEE7的标准实现,其中WebSocket 1.1规范给予实现。在使用其开发的依赖环境是Tomcat8.x JDK7。Tomcat8.x提供了服务器端的实现,客户端实现需要借助其他实现如java_websocket。

 

  Tomcat8.x对WebSocket实现感觉很明朗化了,既然API中定义了WebSocket相关的注解和Session那么Tomcat8.x实现中自然会有相应的处理和实现,下图是简单的关系描述。

 wKioL1R71y-yvpatAAI1MX-cI-o472.jpg

上图解释:

  1. tomcat的WsSession类实现了Java WebSocket API中的Session接口

  2. PojoEndpointBase以及其子类处理与Endpoint相关的类或注解

  3. EndpointConfig,Endpoint都与Session的实现类之间存在依赖关系


   通过了解Java Websocket API和Tomcat8.x对其的实现,认为使用Java WebSocket需要熟悉其中关键类或接口如:Endpoint,EndpointConfig,Client和Server,Encoder和Decoder,Session,MessageHandler。


   上面大致介绍了Tomcat8.x对Java Websocket的实现,有关WebSocket规范的了解信息可以参考:

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

   WebSocket服务器端实现:https://java.net/projects/websocket-spec/pages/WebSocketAPIs

   

下面是通过代码示例来展示基于WebSocket的实时聊天

1.服务器端实现

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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值中有个nickName的参数占位符,该参数占位符称为路径参数,路径参数可以通过方法参数注解(@PathParam)进行设置并且获取;

    在Endpoint注解的类中OnClose,OnOpen,OnError注解的方法只有一个,OnMessage注解的方法可以有多个这个容易理解因为WebSocket可能处理的信息有text,binary,textStream等。


2.客户端实现

  如果使用Maven的话,可以添加java_websocket jar的依赖。

1
2
3
4
5
6
<dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.3.0</version>
            <scope>runtime</scope>
        </dependency>


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


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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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);
        }
    }
}

 说明:

    客户端中要说明的是new Draft_17()对象的创建,通过类名可以得知草案的意思。由于Websocket标准迟迟没有发布,因而之前实现都是依据草案进行,而这里的Draft_17对应的WebSocket版本正是:【"Sec-WebSocket-Version", "13"  】可惜,java_websocket包迟迟没有更新内容,名称出现误解人的地方。


3.开始聊天

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

  下面是聊天的截图,分别为Tom和Jack。

 

wKiom1R74rWjTwRAAAENkee9KzI276.jpg

wKioL1R74z6z27UsAAFZ621cRio571.jpg

 

至此,关于使用Tomcat8和JDK7基于WebSocket实现的聊天示例就结束了。



本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1584957,如需转载请自行联系原作者

相关文章
|
1月前
|
Java
基于Tomcate、java、websocket 简单在线聊天
基于Tomcate、java、websocket 简单在线聊天
|
1月前
|
存储 JavaScript 前端开发
SpringBoot集成WebSocket实现及时通讯聊天功能!!!
SpringBoot集成WebSocket实现及时通讯聊天功能!!!
73 0
|
1月前
|
开发框架 JavaScript 前端开发
如何使用SpringBoot和Netty实现一个WebSocket服务器,并配合Vue前端实现聊天功能?
如何使用SpringBoot和Netty实现一个WebSocket服务器,并配合Vue前端实现聊天功能?
85 0
|
2月前
|
移动开发 监控 网络协议
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
|
2月前
|
前端开发 JavaScript
Netty异步NIO框架(二)websocket 前端后端聊天 私聊及群聊
Netty异步NIO框架(二)websocket 前端后端聊天 私聊及群聊
|
7月前
|
Java
WebSocket实现线上聊天就是这么简单!
WebSocket实现线上聊天就是这么简单!
WebSocket实现线上聊天就是这么简单!
|
8月前
|
JavaScript 前端开发
vue基于websocket实现智能聊天及吸附动画效果
vue基于websocket实现智能聊天及吸附动画效果
vue基于websocket实现智能聊天及吸附动画效果
|
前端开发 Java 应用服务中间件
SpringBoot整合Netty搭建高性能Websocket服务器(实现聊天功能)
之前使用Springboot整合了websocket,实现了一个后端向前端推送信息的基本小案例,这篇文章主要是增加了一个新的框架就是Netty,实现一个高性能的websocket服务器,并结合前端代码,实现一个基本的聊天功能。你可以根据自己的业务需求进行更改。 这里假设你已经了解了Netty和websocket的相关知识,仅仅是想通过Springboot来整合他们。根据之前大家的需求,代码已经上传到了github上。在文末给出。 废话不多说,直接看步骤代码。
1234 0
SpringBoot整合Netty搭建高性能Websocket服务器(实现聊天功能)
相关产品
云迁移中心
推荐文章
更多