WebSocket 的使用
Java 控制台程序实现类似广播功能
服务器端代码
添加 maven 依赖
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
服务器端代码
package com.seliote.web.http;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* 每次有 WebSocket 连接请求都会创建一个该类的实例
*/
@ServerEndpoint(value = "/broadcast")
public class SocketServer {
private static final List<Session> onlinePeople = new ArrayList<>();
@OnOpen
public void onOpen(Session aSession) {
System.out.println(System.currentTimeMillis() + ": OnOpen:::" + onlinePeople.size() + 1);
if (!onlinePeople.contains(aSession)) {
onlinePeople.add(aSession);
}
}
// 该方法是用于被动接收信息的
@OnMessage
public void onMessage(Session aSession, String aS) throws IOException {
System.out.println(System.currentTimeMillis() + ": OnMessage:::" + aS);
for (Session session : onlinePeople) {
session.getBasicRemote().sendText(aS);
}
}
// OnMessage 可以有多个不同签名的
@OnMessage
public void onMessage(Session aSession, InputStream aInputStream) {
System.out.println(System.currentTimeMillis() + ": OnMessage");
// TODO
}
/**
* 每次有客户端异常关闭该方法也会调用
* @param aSession
* @param aCloseReason
*/
@OnClose
public void onClose(Session aSession, CloseReason aCloseReason) {
System.out.println(System.currentTimeMillis() + ": OnClose:::" + aCloseReason.getReasonPhrase());
if (onlinePeople.contains(aSession)) {
onlinePeople.remove(aSession);
}
}
@OnError
public void onError(Session aSession, Throwable aThrowable) {
System.out.println(System.currentTimeMillis() + ": OnError");
aThrowable.printStackTrace();
}
}
如果连接时需要携带客户端信息,那么可以在路径中加入参数,如客户端路径加入用户 Token 变为 127.0.0.1/broadcast/123456,服务器端的标注就可改为 @ServerEndpoint(value = "/broadcast/{token}") ,之后的 @OnOpen 方法中就可以有一个 @PathParam("token") String aToken 代表客户端传入的 Token
客户端代码
添加 maven 依赖,注意这里使用的是 tyrus-standalone-client 而非 javax.websocket-client-api 后者会报错
<dependency>
<groupId>org.glassfish.tyrus.bundles</groupId>
<artifactId>tyrus-standalone-client</artifactId>
<version>1.3.3</version>
<scope>compile</scope>
</dependency>
客户端代码
package com.seliote;
import javax.websocket.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Scanner;
@ClientEndpoint
public class Demo {
private static Session sSession;
public static void main(String... args) throws URISyntaxException, DeploymentException, IOException {
// https 协议对应使用 wss
URI uri = new URI("ws", "127.0.0.1:8080", "/broadcast", null, null);
// 通过 ContainerProvider 的 static 方法 getWebSocketContainer() 获得 WebSocketContainer
sSession = ContainerProvider.getWebSocketContainer().connectToServer(Demo.class, uri);
try (Scanner scanner = new Scanner(System.in)) {
String broadcastMsg = "";
while (true) {
broadcastMsg = scanner.nextLine();
// 通过 Session 对象主动发送信息
sSession.getBasicRemote().sendText(broadcastMsg);
//sSession.getBasicRemote().getSendStream().write(....);
}
}
}
@OnOpen
public void onOpen() {
System.out.println(System.currentTimeMillis() + ": OnOpen ");
}
// 该方法是用于被动接收信息的
@OnMessage
public void onMessage(String aS) {
System.out.println(System.currentTimeMillis() + ": OnMessage::: " + aS);
}
}
在一个客户端输入信息后服务器会及时收到信息并广播给所有在线的客户端
------------------------------------------2019.01.09 更新
如果需要支持相应的实体类型,WebSocket 服务器端大概长 这样,而客户端配置如下
Maven 依赖(这里用了 JSONObject 而不是服务器端的 Jackson)
<dependency>
<groupId>org.glassfish.tyrus.bundles</groupId>
<artifactId>tyrus-standalone-client</artifactId>
<version>1.3.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
<scope>compile</scope>
</dependency>
package com.seliote.demo;
/**
* @author seliote
* @date 2019-01-09
* @description WebSocket 信息实体
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public class BroadcastMsg {
private String mSessionId;
private String mTimestamp;
private String mMsg;
public BroadcastMsg() {}
public BroadcastMsg(String aSessionId, String aTimestamp, String aMsg) {
mSessionId = aSessionId;
mTimestamp = aTimestamp;
mMsg = aMsg;
}
public String getSessionId() {
return mSessionId;
}
public void setSessionId(String aSessionId) {
mSessionId = aSessionId;
}
public String getTimestamp() {
return mTimestamp;
}
public void setTimestamp(String aTimestamp) {
mTimestamp = aTimestamp;
}
public String getMsg() {
return mMsg;
}
public void setMsg(String aMsg) {
mMsg = aMsg;
}
@Override
public String toString() {
return mSessionId + " - " + mTimestamp + " - " + mMsg;
}
}
package com.seliote.demo;
import org.json.JSONObject;
import javax.websocket.Decoder;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
/**
* @author seliote
* @date 2019-01-09
* @description BroadcastMsg 用于 WebSocket 的编码与解码器
*/
public class BroadcastMsgCoder implements Encoder.BinaryStream<BroadcastMsg>, Decoder.BinaryStream<BroadcastMsg> {
@Override
public void init(EndpointConfig aEndpointConfig) {
}
@Override
public void destroy() {
}
@Override
public void encode(BroadcastMsg aBroadcastMsg, OutputStream aOutputStream) throws IOException {
aOutputStream.write(new JSONObject(aBroadcastMsg).toString().getBytes(StandardCharsets.UTF_8));
}
@Override
public BroadcastMsg decode(InputStream aInputStream) throws IOException {
byte[] buffer = new byte[1024];
int length;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while ((length = aInputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, length);
}
String json = new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(json);
return new BroadcastMsg(
jsonObject.getString("sessionId"),
jsonObject.getString("timestamp"),
jsonObject.getString("msg")
);
}
}
package com.seliote.demo;
import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.EncodeException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Scanner;
@ClientEndpoint(
encoders = BroadcastMsgCoder.class,
decoders = BroadcastMsgCoder.class
)
public class Demo {
public static void main(String... args) throws URISyntaxException, DeploymentException, IOException {
// https 协议对应使用 wss
URI uri = new URI("ws", "127.0.0.1:8080", "/time/1", null, null);
// 通过 ContainerProvider 的 static 方法 getWebSocketContainer() 获得 WebSocketContainer
Session session = ContainerProvider.getWebSocketContainer().connectToServer(Demo.class, uri);
try (Scanner scanner = new Scanner(System.in)) {
//noinspection InfiniteLoopStatement
while (true) {
// 通过 Session 对象主动发送信息
try {
String msg = scanner.nextLine();
BroadcastMsg broadcastMsg = new BroadcastMsg(
session.getId(),
System.currentTimeMillis() + "",
msg
);
session.getBasicRemote().sendObject(broadcastMsg);
} catch (EncodeException exp) {
exp.printStackTrace();
}
//sSession.getBasicRemote().getSendStream().write(....);
}
}
}
@OnOpen
public void onOpen() {
System.out.println(System.currentTimeMillis() + ": OnOpen ");
}
@OnMessage
public void onMessage(String aS) {
System.out.println(System.currentTimeMillis() + ": OnMessage::: " + aS);
}
@OnMessage
public void onMessage(BroadcastMsg aBroadcastMsg) {
System.out.println(aBroadcastMsg);
}
}
WebSocket 的使用的更多相关文章
- 漫扯:从polling到Websocket
Http被设计成了一个单向的通信的协议,即客户端发起一个request,然后服务器回应一个response.这让服务器很为恼火:我特么才是老大,我居然不能给小弟发消息... 轮询 老大发火了,小弟们自 ...
- 细说WebSocket - Node篇
在上一篇提高到了 web 通信的各种方式,包括 轮询.长连接 以及各种 HTML5 中提到的手段.本文将详细描述 WebSocket协议 在 web通讯 中的实现. 一.WebSocket 协议 1. ...
- java使用websocket,并且获取HttpSession,源码分析
转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...
- WebSocket - ( 一.概述 )
说到 WebSocket,不得不提 HTML5,作为近年来Web技术领域最大的改进与变化,包含CSS3.离线与存储.多媒体.连接性( Connectivity )等一系列领域,而即将介绍的 WebSo ...
- php+websocket搭建简易聊天室实践
1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...
- Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
- Cowboy 开源 WebSocket 网络库
Cowboy.WebSockets 是一个托管在 GitHub 上的基于 .NET/C# 实现的开源 WebSocket 网络库,其完整的实现了 RFC 6455 (The WebSocket Pro ...
- 借助Nodejs探究WebSocket
文章导读: 一.概述-what's WebSocket? 二.运行在浏览器中的WebSocket客户端+使用ws模块搭建的简单服务器 三.Node中的WebSocket 四.socket.io 五.扩 ...
- 细说websocket - php篇
下面我画了一个图演示 client 和 server 之间建立 websocket 连接时握手部分,这个部分在 node 中可以十分轻松的完成,因为 node 提供的 net 模块已经对 socket ...
- webSocket and LKDBHelper的使用说明
socketket与lkdbhelper来处理数据 客户需求: 当我们有需要从自己的后台推送消息给我们的用户时,用户需要实时的接收到来自我们的推送消息.前提是没有使用第三方的推送框架,那么这个使用we ...
随机推荐
- YouTube 1080P高清视频下载方法
在国内在线视频网站还停留在1080P蓝光的时候,YouTube早已经支持4K和8K分辨率的极清视频.虽然4K和8K的清晰度比1080P高了许多档次,但是大部分人的电脑播放4K视频还是很卡的,所以目前来 ...
- SAP订单编排和流程增强概述
SAP产品里的订单处理,无论是On-Premises解决方案还是云产品,我认为归根到底可以概括成四个字:订单编排,包含两个层次的内容: 1. 单个订单通过业务流程或者工作流驱动的状态迁移: 2. 多种 ...
- 【BZOJ4766】文艺计算姬(prufer序列)
点此看题面 大致题意: 让你求一个两边各有\(n\)和\(m\)个点的完全二分图有多少个生成树. \(prufer\)序列 这是一道比较经典的利用\(prufer\)序列结论求解答案的计数题. 大致思 ...
- Sublime Text 插件 【转】
好厉害,好漂亮. http://www.cnsecer.com/460.html 安装Sublime Text 3插件的方法: 朋友们,小站活着不容易,全靠广告费养着了,如果本文对你有帮助.麻烦动下手 ...
- Intellij IDEA中Maven解决依赖失效
最近在折腾Maven和Sonatype的Nexus, 倒霉催的国内和公司网络... Nexus配合finalspeed或者kcptun倒是很给力, 但是Intellij就经常出问题, 出现红字也不动 ...
- 随便扯扯React生命周期 --《爱看不看系列》
生命周期嘛,顾名思义,就是说组件这辈子从生下来到死掉经历的事情.先来看看一张图片,温故温故,如图: 你会发现有些周期的名字都能找出点规律,我找到的规律是凡是 Will 字母的,表示该钩子函数会在该生命 ...
- 使用带有字符串的data-ng-bind
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- javascript跳转页面
<script type="text/javascript"> function openNewTab() { parent.addExampleTab({ id: a ...
- Oracle单行函数用法
单行函数分为五种类型:字符函数.数值函数.日期函数.转换函数.通用函数. 1.字符函数: 对于输入的字符转换为需要转为的字符或数值. upper()大写 --小写字母转为大写字母 --对于表指定的字符 ...
- 一位90后程序员的自述:如何从年薪3w到30w
▌自我介绍 引用赵真老师的一首歌<过去不是错>中的一句话:过去不是过错,毕竟我们也开心过.过去不是过错,何必愧疚不知所措. 我们这一代人,我相信多少都会有人和我一样,坚持过一个游戏,叫 D ...