学习WebSocket一(WebSocket初识)
Java EE 7 去年刚刚发布了JSR356规范,使得WebSocket的Java API得到了统一,Tomcat从7.0.47开始支持JSR356,这样一来写WebSocket的时候,所用的代码都是可以一样的。今天终于体验了一把Tomcat发布的WebSocket,用着很爽,下面把这一历程分享给大家。
界面效果 | 服务端代码 |
打开一个页面,首先点击Connect,保证连接到Websocket,
再在输入框里输入"I am angel1!",
点击Echo message,可以看到下面框里输入Sent和Received信息。
我们看一下它的代码是怎么实现的。 |
@ServerEndpoint("/websocket/echoAnnotation")
public class EchoAnnotation {
@OnMessage
public void echoTextMessage(Session session, String msg, boolean last) {
try {
if (session.isOpen()) {
session.getBasicRemote().sendText(msg, last);
}
} catch (IOException e) {
try {
session.close();
} catch (IOException e1) {
// Ignore
}
}
}
@OnMessage
public void echoBinaryMessage(Session session, ByteBuffer bb,
boolean last) {
try {
if (session.isOpen()) {
session.getBasicRemote().sendBinary(bb, last);
}
} catch (IOException e) {
try {
session.close();
} catch (IOException e1) {
// Ignore
}
}
} |
界面效果 | 服务端代码 |
打开第一个页面,它会告诉你,你已经加入聊天了。 分析代码,就是一个新连接,会自动实例化一个ChatAnnotation, 这些ChatAnnotation对象共用同一些属性, 最重要的就是Set<ChatAnnotation> conncetions, 在OnOpen处把自身实例加入到conncetions中,并广播消息。 广播消息,是轮循conncetions并发送消息。 在界面输入对话框处输入文字,回车,消息就会发送到服务端。 第一个页面: 第二个页面: |
@ServerEndpoint(value = "/websocket/chat")
public class ChatAnnotation {
private static final String GUEST_PREFIX = "Guest";
private static final AtomicInteger connectionIds = new AtomicInteger(0);
private static final Set<ChatAnnotation> connections =
new CopyOnWriteArraySet<ChatAnnotation>();
private final String nickname;
private Session session;
public ChatAnnotation() {
nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
}
@OnOpen
public void start(Session session) {
this.session = session;
connections.add(this);
String message = String.format("* %s %s", nickname, "has joined.");
broadcast(message);
}
@OnClose
public void end() {
connections.remove(this);
String message = String.format("* %s %s",
nickname, "has disconnected.");
broadcast(message);
}
@OnMessage
public void incoming(String message) {
// Never trust the client
String filteredMessage = String.format("%s: %s",
nickname, HTMLFilter.filter(message.toString()));
broadcast(filteredMessage);
}
private static void broadcast(String msg) {
for (ChatAnnotation client : connections) {
try {
client.session.getBasicRemote().sendText(msg);
} catch (IOException e) {
connections.remove(client);
try {
client.session.close();
} catch (IOException e1) {
// Ignore
}
String message = String.format("* %s %s",
client.nickname, "has been disconnected.");
broadcast(message);
}
}
}
} |
@ServerEndpoint(value = "/websocket/snake")
public class SnakeAnnotation {
public static final int PLAYFIELD_WIDTH = 640;
public static final int PLAYFIELD_HEIGHT = 480;
public static final int GRID_SIZE = 10;
private static final AtomicInteger snakeIds = new AtomicInteger(0);
private static final Random random = new Random();
private final int id;
private Snake snake;
|
public static String getRandomHexColor() {
float hue = random.nextFloat();
// sat between 0.1 and 0.3
float saturation = (random.nextInt(2000) + 1000) / 10000f;
float luminance = 0.9f;
Color color = Color.getHSBColor(hue, saturation, luminance);
return '#' + Integer.toHexString(
(color.getRGB() & 0xffffff) | 0x1000000).substring(1);
}
public static Location getRandomLocation() {
int x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH));
int y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT));
return new Location(x, y);
}
private static int roundByGridSize(int value) {
value = value + (GRID_SIZE / 2);
value = value / GRID_SIZE;
value = value * GRID_SIZE;
return value;
}
public SnakeAnnotation() {
this.id = snakeIds.getAndIncrement();
}
|
@OnOpen
public void onOpen(Session session) {
this.snake = new Snake(id, session);
SnakeTimer.addSnake(snake);
StringBuilder sb = new StringBuilder();
for (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator();
iterator.hasNext();) {
Snake snake = iterator.next();
sb.append(String.format("{id: %d, color: '%s'}",
Integer.valueOf(snake.getId()), snake.getHexColor()));
if (iterator.hasNext()) {
sb.append(',');
}
}
SnakeTimer.broadcast(String.format("{'type': 'join','data':[%s]}",
sb.toString()));
}
@OnMessage
public void onTextMessage(String message) {
if ("west".equals(message)) {
snake.setDirection(Direction.WEST);
} else if ("north".equals(message)) {
snake.setDirection(Direction.NORTH);
} else if ("east".equals(message)) {
snake.setDirection(Direction.EAST);
} else if ("south".equals(message)) {
snake.setDirection(Direction.SOUTH);
}
} |
@OnClose
public void onClose() {
SnakeTimer.removeSnake(snake);
SnakeTimer.broadcast(String.format("{'type': 'leave', 'id': %d}",
Integer.valueOf(id)));
}
@OnError
public void onError(Throwable t) throws Throwable {
// Most likely cause is a user closing their browser. Check to see if
// the root cause is EOF and if it is ignore it.
// Protect against infinite loops.
int count = 0;
Throwable root = t;
while (root.getCause() != null && count < 20) {
root = root.getCause();
count ++;
}
if (root instanceof EOFException) {
// Assume this is triggered by the user closing their browser and
// ignore it.
} else {
throw t;
}
} |
界面和ClientEndpoit |
入口代码
|
下面是调用了echoAnnotation的websocket的客户端与服务端交互过程。
同样是客户端发给服务端一个消息,服务端收到后发给客户端,
客户端收到后显示出来。
客户端代码也很简单,没有什么逻辑,只管把接收的打印出来就行了。
需要注意的是,需要引用的jar包只在Java EE 7中包含。
包括javax.websocket-api.jar、tyrus-client.jar、
tyrus-container-grizzly.jar、tyrus-core.jar、
tyrus-websocket-core.jar、tyrus-spi.jar、tyrus-server.jar、
nucleus-grizzly-all.jar
同样的也可以调用其它的websocket,比如chat...使用起来非常方便。
@ClientEndpoint
public class MyClient {
@OnOpen
public void onOpen(Session session) {
}
@OnMessage
public void onMessage(String message) {
System.out.println("Client onMessage: " + message);
}
@OnClose
public void onClose() {
}
} |
public class Main {
private static String uri = "ws://localhost/examples/websocket/echoAnnotation";
private static Session session;
private void start() {
WebSocketContainer container = null;
try {
container = ContainerProvider.getWebSocketContainer();
} catch (Exception ex) {
System.out.println("error" + ex);
}
try {
URI r = URI.create(uri);
session = container.connectToServer(MyClient.class, r);
} catch (DeploymentException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Main client = new Main();
client.start();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = "";
try {
do {
input = br.readLine();
if (!input.equals("exit"))
client.session.getBasicRemote().sendText(input);
} while (!input.equals("exit"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} |
学习WebSocket一(WebSocket初识)的更多相关文章
- Spring 学习——基于Spring WebSocket 和STOMP实现简单的聊天功能
本篇主要讲解如何使用Spring websocket 和STOMP搭建一个简单的聊天功能项目,里面使用到的技术,如websocket和STOMP等会简单介绍,不会太深,如果对相关介绍不是很了解的,请自 ...
- HTML5学习总结-08 WebSocket 服务器推送
一 WebSocket 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展 ...
- 学习html5的WebSocket连接
1.什么是WebSocket WebSocket 是一种自然的全双工.双向.单套接字连接.使用WebSocket,你的HTTP 请求变成打开WebSocket 连接(WebSocket 或者WebSo ...
- Python Web学习笔记之WebSocket 通信过程与实现
一.什么是 WebSocket ? WebSocket 是一种标准协议,用于在客户端和服务端之间进行双向数据传输.但它跟 HTTP 没什么关系,它是基于 TCP 的一种独立实现. 以前客户端想知道服务 ...
- 【HTML5 WebSocket】WebSocket对象特性和方法
<HTML5 WebSocket权威指南>学习笔记&3 WebSocket方法的对象特性 1. WebSocket方法 a. send方法 send方法用于在WebSocket连接 ...
- 【WebSocket】WebSocket介绍
1.背景 在WebSocket出现之前客户端向服务器发出请求是通过http协议实现的,而http协议有个特点是通行请求只能由客户端发起,然后服务端响应查询结果,HTTP 协议没法让服务器主动向客户端推 ...
- Linux学习之CentOS(三)--初识linux的文件系统以及用户组等概念
Linux学习之CentOS(三)--初识linux的文件系统以及用户组等概念 进入到了Linux学习之CentOS第三篇了,这篇文章主要记录下对linux文件系统的初步认识,以及用户组.用户权限.文 ...
- Linux学习之CentOS(二)--初识linux的一些常用命令
Linux学习之CentOS(二)--初识linux的一些常用命令 在VM上安装完了CentOS6.4以后,看着linux系统成功跑起来,心里小激动了一把......但是前方学习的道路还很遥远... ...
- day 81 Vue学习一之vue初识
Vue学习一之vue初识 本节目录 一 Vue初识 二 ES6的基本语法 三 Vue的基本用法 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 vue初识 vue称为渐进式js ...
- nginx支持websocket及websocket部分原理介绍
nginx支持websocket及websocket部分原理介绍最近ipc通过websocket与server进行通行,经过无法通过nginx进行反向代理,只有直连nodejs端口.而且部署到阿里云用 ...
随机推荐
- 2014年北京网络赛 Instrusive HDU 5040 题解 优先队列
网赛的时候看了这道题,发现就是平常的那种基础搜索题. 由于加了一个特殊条件:可以一次消耗3秒或原地停留1秒. 那就不能使用简单的队列了,需要使用优先队列才行. 题意 告诉一副地图:一个起点,一个终点, ...
- Windows命令计算MD5与SHA1/256值
certutil -hashfile file MD5 certutil -hashfile file SHA1 certutil -hashfile file SHA256 示例如下:
- Javascript替代eval方法
Javascript替代eval方法 通常我们在使用ajax获取到后台返回的json数据时,都要使用 eval 这个方法将json字符串转换成对象数组, 像这样: obj = eval('('+dat ...
- Codeforces 949E Binary Cards
Description 给出一个长度为 \(n\) 的数组,求使得用最少数量的 \(2^k\) 或 \(-2^k\) 的数,使得数组中的每一个元素都可以被你选出的 \(2\) 的次幂表示 题面 Sol ...
- Windows开启telnet命令
1.点击开始 → 运行 → 输入telnet,回车. 2.点击启用或关闭Windows功能 3.找到Telnet客户端,勾选,点击确认 4.搞定,测试一下 打开CMD,在出来的DOS界面里,输入tel ...
- 新建文件可选类型插件:SublimeTmpl
介绍:SublimeTmpl,新建文件可选类型.编辑模版在:SublimeTmpl\templates"文件夹修改 1.安装: 通过 Package Control Package Cont ...
- mysql字符集的修改
修改数据库字符集: 代码如下: ALTER DATABASE db_name DEFAULT CHARACTER SET character_name [COLLATE ...]; 把表默认的字符 ...
- redis(3)发布订阅
一.发布/订阅模式 在软件工程里面,发布/订阅是一种消息模式,这种模式旨在将消息发送者和消息接收者解耦.发送者不需要关心将消息发送给谁,接收者也不需要知道消息的发送者是谁.发送者将消息发布以后就结束动 ...
- redis的持久化方式
redis有两种持久化方式,第一种是基于快照的持久化方式,第二种是基于文件追加的持久化方式 一.基于快照的持久化 1.修改redis.conf配置文件,开启基于快照的持久化方式 2.修改持久化文件存放 ...
- 解决Openwrt安装插件提示一下错误的办法
解决Openwrt安装插件提示一下错误的办法 Openwrt安装17ce插件,提示一下错误: Collected errors: * check_data_file_clashes: Package ...