使用 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<ChatEndpoint> 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

<html>
<head>
<title>使用 WebSocket 通信</title>
</head>
<body>
<div style="width: 600px; height:240px;overflow-y: auto;border: 1px solid #333;" id="show"> </div>
<input type="text" size="80" id="msg" name="msg" placeholder="请输入聊天内容"/ >
<input type="button" value="发送" id="sendBtn" name="sendBtn" /> <script>
window.onload = function() {
// 创建 WebSocket 对象
var webSocket = new WebSocket("ws://127.0.0.1:8080/jsp/websocket/chat");
var sendMsg = function() {
var inputElement = document.getElementById('msg');
// 发送消息
webSocket.send(inputElement.value);
// 清空单行文本框
inputElement.value = "";
};
var send = function(event) {
if (event.keyCode == 13) {
sendMsg();
}
}; webSocket.onopen = function() {
// 为 onmessage 事件绑定监听器,接收消息
webSocket.onmessage = function(event) {
var show = document.getElementById('show');
// 接收并显示消息
show.innerHTML += event.data + "<br/>";
show.scrollTop = show.scrollHeight;
};
document.getElementById('msg').onkeydown = send;
document.getElementById('sendBtn').onclick = sendMsg;
};
webSocket.onclose = function() {
// document.getElementById('msg').onkeydown = null;
// document.getElementById('sendBtn').onclick = null;
console.log('WebSocket已经被关闭');
};
}
</script>
</body>
</html>

  

  

tomcat8 的 websocket 支持的更多相关文章

  1. Spring 4 官方文档学习(十四)WebSocket支持

    个人提示:如果需要用到页面推送,高频且要低延迟,WebSocket无疑是最佳选择.否则还是轮询和long polling吧. 做了一个小demo放在码云上,有兴趣的可以看一下,简单易懂:websock ...

  2. 咏南中间件增加WEBSOCKET支持

    咏南中间件增加WEBSOCKET支持

  3. ASP.NET Core 中的 WebSocket 支持(转自MSDN)

    本文介绍 ASP.NET Core 中 WebSocket 的入门方法. WebSocket (RFC 6455) 是一个协议,支持通过 TCP 连接建立持久的双向信道. 它用于从快速实时通信中获益的 ...

  4. Netty 框架学习 —— 添加 WebSocket 支持

    WebSocket 简介 WebSocket 协议是完全重新设计的协议,旨在为 Web 上的双向数据传输问题提供一个切实可行的解决方案,使得客户端和服务器之间可以在任意时刻传输消息 Netty 对于 ...

  5. 为libevent添加websocket支持(上)

    在跨平台网络基础库中,libevent与asio近年来使用比较广泛.asio对boost的依赖太大,个人认为发展前途堪忧,尤其asio对http没有很好的支持也是缺点之一. libevent对http ...

  6. 微信小游戏websocket支持https/wss

    公司新项目需要支持wss,解决方法如下: https://blog.csdn.net/peter_teng/article/details/82866613 proxy_pass http://web ...

  7. k8s-ingress配置websocket支持

    具体来说,使用的ingress-controller不一样,有关的设置也不太一样 Kubernetes Ingress Controller (k8s官方) 参考 http://github.com/ ...

  8. tomcat8热部署配置--maven自动发布项目到tomcat8(如何支持远程访问部署)

    1.tomcat8实现热部署的配置  我们实现热部署后,自然就可以通过maven操作tomcat了,所以就需要maven取得操作tomcat的权限,现在这一步就是配置tomcat的可操作权限. #进入 ...

  9. nginx 设置websocket支持

    #websocket======相关 proxy_read_timeout 60m; proxy_http_version 1.1; proxy_set_header Upgrade $http_up ...

随机推荐

  1. Python3实现机器学习经典算法(三)ID3决策树

    一.ID3决策树概述 ID3决策树是另一种非常重要的用来处理分类问题的结构,它形似一个嵌套N层的IF…ELSE结构,但是它的判断标准不再是一个关系表达式,而是对应的模块的信息增益.它通过信息增益的大小 ...

  2. ES6的新特性(1)——ES6 的概述

    ES6 的概述 首先,感谢马伦老师的ES6新特性的教程. ECMAScript 和 JavaScript 的关系是 ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前 ...

  3. 关于jsonp跨域的 实现

    1.实现原理    1.把接口写在 script标签的src 中 这个接口就可以访问(不会存在跨域问题  因为接口在浏览器地址栏是可以访问的  会返回json字符串); 2.直接写不可以  因为正常情 ...

  4. MySQL的课堂的实践

    MySQL的课堂的实践 基本认识 如今的数据库有几种是主流,分别是:Oracle Database.Informix.SQL Server.PostgreSQL.MySQL等,我们现在学习的MySQL ...

  5. mysql You can't specify target table 'xxx' for update in FROM clause

    含义:您不能在子句中为更新指定目标表'xxx'. 错误描述:删除语句中直接含select,如下: DELETE FROM meriadianannotation WHERE SeriesID IN ( ...

  6. 机器学习实战第二章----KNN

    tile的使用方法 tile(A,n)的功能是把A数组重复n次(可以在列方向,也可以在行方向) argsort()函数 argsort()函数返回的是数组中值从大到小的索引值 dict.get()函数 ...

  7. 缓存-System.Web.Caching.Cache

    实现 Web 应用程序的缓存. 每个应用程序域创建一个此类的实例,只要应用程序域将保持活动状态,保持有效. 有关此类的实例的信息,请通过Cache的属性HttpContext对象或Cache属性的Pa ...

  8. iOS- 利用AFNetworking(AFN) - 实现文件上传

    官方建议AFN的使用方法 1. 定义一个全局的AFHttpClient:包含有 1> baseURL 2> 请求 3> 操作队列 NSOperationQueue 2. 由AFHTT ...

  9. 团队项目-BUG排查-ADT工程 To Android Studio 一整天的排查日记

    4-22 10:44至4-23 0:45 ①打开Eclipse从Github上Clone MathsApp到本机,报错'Unable to resolve target'android-19' ②尝试 ...

  10. iOS界面设计之基础控件的学习 --- UITextField

    学习iOS界面设计也有段时间了,每次写到一些基础控件(如:UILable . UITextField)的时候就深觉应该总结一个函数来实现这些基础控件的属性设置,所以下面就是我对UITextField的 ...