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<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 支持的更多相关文章
- Spring 4 官方文档学习(十四)WebSocket支持
个人提示:如果需要用到页面推送,高频且要低延迟,WebSocket无疑是最佳选择.否则还是轮询和long polling吧. 做了一个小demo放在码云上,有兴趣的可以看一下,简单易懂:websock ...
- 咏南中间件增加WEBSOCKET支持
咏南中间件增加WEBSOCKET支持
- ASP.NET Core 中的 WebSocket 支持(转自MSDN)
本文介绍 ASP.NET Core 中 WebSocket 的入门方法. WebSocket (RFC 6455) 是一个协议,支持通过 TCP 连接建立持久的双向信道. 它用于从快速实时通信中获益的 ...
- Netty 框架学习 —— 添加 WebSocket 支持
WebSocket 简介 WebSocket 协议是完全重新设计的协议,旨在为 Web 上的双向数据传输问题提供一个切实可行的解决方案,使得客户端和服务器之间可以在任意时刻传输消息 Netty 对于 ...
- 为libevent添加websocket支持(上)
在跨平台网络基础库中,libevent与asio近年来使用比较广泛.asio对boost的依赖太大,个人认为发展前途堪忧,尤其asio对http没有很好的支持也是缺点之一. libevent对http ...
- 微信小游戏websocket支持https/wss
公司新项目需要支持wss,解决方法如下: https://blog.csdn.net/peter_teng/article/details/82866613 proxy_pass http://web ...
- k8s-ingress配置websocket支持
具体来说,使用的ingress-controller不一样,有关的设置也不太一样 Kubernetes Ingress Controller (k8s官方) 参考 http://github.com/ ...
- tomcat8热部署配置--maven自动发布项目到tomcat8(如何支持远程访问部署)
1.tomcat8实现热部署的配置 我们实现热部署后,自然就可以通过maven操作tomcat了,所以就需要maven取得操作tomcat的权限,现在这一步就是配置tomcat的可操作权限. #进入 ...
- nginx 设置websocket支持
#websocket======相关 proxy_read_timeout 60m; proxy_http_version 1.1; proxy_set_header Upgrade $http_up ...
随机推荐
- ConcurrentHashMap(JDK1.8)为什么要放弃Segment
今天看到一篇博客:jdk1.8的HashMap和ConcurrentHashMap,我想起了前段时间面试的一个问题:ConcurrentHashMap(JDK1.8)为什么要使用synchronize ...
- 基于C#的机器学习--机器学习的基本知识
机器学习的基本知识 ,…用n个观测值测量.但我们不再对Y的预测感兴趣,因为我们不再有Y了,我们唯一感兴趣的是在已有的特征上发现数据模式: 在前面的图中,我们可以看到这样的数据本身更适合于非线性方法 ...
- python错误记录
在主函数里调用其他函数时形参顺序要一致 错例如下:
- python socket详解
Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...
- DL开源框架Caffe | 模型微调 (finetune)的场景、问题、技巧以及解决方案
转自:http://blog.csdn.net/u010402786/article/details/70141261 前言 什么是模型的微调? 使用别人训练好的网络模型进行训练,前提是必须和别人 ...
- goroutine与channels
goroutine(协程) 大家都知道java中的线程Thread,golang没有提供Thread的功能,但是提供了更轻量级的goroutine(协程),协程比线程更轻,创办一个协程很简单,只需要g ...
- 第8章 Linux磁盘与文件系统管理
认识EXT2文件系统 文件的系统特性 Linux的正规文件系统为Ext2 文件数据除了文件实际内容外,还包括其他属性(文件权限.文件属性). 文件系统将这两部分数据分别存放在不同的块,权限和属性放在i ...
- Spark Shuffle之Sort Shuffle
源文件放在github,随着理解的深入,不断更新,如有谬误之处,欢迎指正.原文链接https://github.com/jacksu/utils4s/blob/master/spark-knowled ...
- 使用 virt-install 创建虚拟机
使用 virt-install 创建虚拟机 virt-install --help 使用 qemu-kvm 创建虚拟机 介绍 1:命令路径:/usr/libexec/qemu-kvm 2:添加至环 ...
- fsockopen 异步非阻塞式请求数据
index.php <?php ini_set ( "max_execution_time", "0" ); // 要传递的数据 $form_data = ...