【Netty】Netty入门之WebSocket小例子
服务端:
引入Netty依赖
<!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.27.Final</version>
</dependency>
WebSocket全局配置类的编写
/**
* 存储整个工程的全局配置
*/
public class NettyConfig { /**
* 存储每一个客户端接入进来时的channel对象
*/
public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); }
接收/处理/响应客户端websocket请求的核心业务处理类
package com.imooc.netty; import java.util.Date;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil; /**
* 接收/处理/响应客户端websocket请求的核心业务处理类
*/
public class MyWebSocketHandler extends SimpleChannelInboundHandler<Object> { private WebSocketServerHandshaker handshaker;
private static final String WEB_SOCKET_URL = "ws://localhost:8888/websocket"; /**
* 客户端与服务端创建连接的时候调用
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
NettyConfig.group.add(ctx.channel());
System.out.println("客户端与服务端连接开启...");
} /**
* 客户端与服务端断开连接的时候调用
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
NettyConfig.group.remove(ctx.channel());
System.out.println("客户端与服务端连接关闭...");
} /**
* 服务端接收客户端发送过来的数据结束之后调用
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} /**
* 工程出现异常的时候调用
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
} /**
* 服务端处理客户端websocket请求的核心方法
*/
protected void channelRead0(ChannelHandlerContext context, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
// 处理客户端向服务端发起http握手请求的业务
this.handHttpRequest(context, (FullHttpRequest) msg);
}else if (msg instanceof WebSocketFrame) {
// 处理websocket连接业务
this.handWebsocketFrame(context, (WebSocketFrame) msg);
}
} /**
* 处理客户端与服务端之前的websocket业务
*/
private void handWebsocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){
// 判断是否是关闭websocket的指令
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(), (CloseWebSocketFrame)frame.retain());
} // 判断是否是ping消息
if (frame instanceof PingWebSocketFrame) {
ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
return;
} // 判断是否是二进制消息,如果是二进制消息,抛出异常
if (!(frame instanceof TextWebSocketFrame)){
System.out.println("目前我们不支持二进制消息");
throw new RuntimeException("【"+this.getClass().getName()+"】不支持消息");
} // 返回应答消息
// 获取客户端向服务端发送的消息
String request = ((TextWebSocketFrame) frame).text();
System.out.println("服务端收到客户端的消息====>>>" + request);
TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString() + ctx.channel().id() + " ===>>> " + request);
// 群发,服务端向每个连接上来的客户端群发消息
NettyConfig.group.writeAndFlush(tws);
}
/**
* 处理客户端向服务端发起http握手请求的业务
*/
private void handHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req){
if (!req.decoderResult().isSuccess() || !("websocket".equals(req.headers().get("Upgrade")))) {
this.sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
return;
}
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(WEB_SOCKET_URL, null, false);
handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
}else{
handshaker.handshake(ctx.channel(), req);
}
} /**
* 服务端向客户端响应消息
*/
private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req,
DefaultFullHttpResponse res){
if (res.status().code() != 200) {
ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
res.content().writeBytes(buf);
buf.release();
}
// 服务端向客户端发送数据
ChannelFuture f = ctx.channel().writeAndFlush(res);
if (res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
} }
WebSocket初始化连接时各个组件的类实现
package com.imooc.netty; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler; /**
* 初始化连接时候的各个组件
*/
public class MyWebSocketChannelHandler extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel e) throws Exception {
e.pipeline().addLast("http-codec", new HttpServerCodec());
e.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
e.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
e.pipeline().addLast("handler", new MyWebSocketHandler());
} }
WebSocket启动类的编写
package com.imooc.netty; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; /**
* 程序的入口,负责启动应用
*/
public class Main { public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workGroup);
b.channel(NioServerSocketChannel.class);
b.childHandler(new MyWebSocketChannelHandler());
System.out.println("服务端开启等待客户端连接....");
Channel ch = b.bind(8888).sync().channel();
ch.closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally{
// 退出程序
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
} }
客户端
编写客户端页面
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset = utf-8"/>
<title>WebSocket客户端</title>
<script type="text/javascript">
var socket;
if(!window.WebSocket){
window.WebSocket = window.MozWebSocket;
} if(window.WebSocket){
socket = new WebSocket("ws://localhost:8888/websocket");
socket.onmessage = function(event){
var ta = document.getElementById('responseContent');
ta.value += event.data + "\r\n";
}; socket.onopen = function(event){
var ta = document.getElementById('responseContent');
ta.value = "你当前的浏览器支持WebSocket,请进行后续操作\r\n";
}; socket.onclose = function(event){
var ta = document.getElementById('responseContent');
ta.value = "";
ta.value = "WebSocket连接已经关闭\r\n";
};
}else{
alert("您的浏览器不支持WebSocket");
} function send(message){
if(!window.WebSocket){
return;
}
if(socket.readyState == WebSocket.OPEN){
socket.send(message);
}else{
alert("WebSocket连接没有建立成功!!");
}
}
</script>
</head>
<body>
<form onSubmit="return false;">
<input type = "text" name = "message" value = ""/>
<br/><br/>
<input type = "button" value = "发送WebSocket请求消息" onClick = "send(this.form.message.value)"/>
<hr color="red"/>
<h2>客户端接收到服务端返回的应答消息</h2>
<textarea id = "responseContent" style = "width:1024px; height:300px"></textarea>
</form>
</body>
</html>
测试
启动服务端,然后打开客户端页面
客户端向服务端发送WebSocket消息,观察结果
服务端控制台:
关闭服务端
【Netty】Netty入门之WebSocket小例子的更多相关文章
- 1、Netty 实战入门详解
一.Netty 简介 Netty 是基于 Java NIO 的异步事件驱动的网络应用框架,使用 Netty 可以快速开发网络应用,Netty 提供了高层次的抽象来简化 TCP 和 UDP 服务器的编程 ...
- 网络应用框架Netty快速入门
一 初遇Netty Netty是什么? Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能.可扩展协议的服务器和客户端 ...
- Selenium WebDriver + Grid2 + RSpec之旅(三) ----入门小例子
Selenium WebDriver + Grid2 + RSpec之旅(三) ----入门小例子 第一个例子都是比较简单的博客园登录界面,就像学习编程语言时候都是从Hello,World!开始. 1 ...
- 一个有趣的小例子,带你入门协程模块-asyncio
一个有趣的小例子,带你入门协程模块-asyncio 上篇文章写了关于yield from的用法,简单的了解异步模式,[https://www.cnblogs.com/c-x-a/p/10106031. ...
- webcat——基于netty的http和websocket框架
代码地址如下:http://www.demodashi.com/demo/12687.html Webcat是一个基于netty的简单.高性能服务端框架,目前提供http和websocket两种协议的 ...
- 基于vue-cli、elementUI的Vue超简单入门小例子
- 这个例子还是比较简单的,独立完成后,能大概知道vue是干嘛的,可以写个todoList的小例子. - 开始写例子之前,先对环境的部署做点简单的介绍,其实和Vue官方的差不多. #如若没有安装过vu ...
- Netty 框架学习 —— 添加 WebSocket 支持
WebSocket 简介 WebSocket 协议是完全重新设计的协议,旨在为 Web 上的双向数据传输问题提供一个切实可行的解决方案,使得客户端和服务器之间可以在任意时刻传输消息 Netty 对于 ...
- springmvc入门的第一个小例子
今天我们探讨一下springmvc,由于是初学,所以简单的了解一下 springmvc的流程,后续会持续更新... 由一个小例子来简单的了解一下 springmvc springmvc是spring框 ...
- Ajax入门小例子
大牛文章:http://www.cnblogs.com/guduoduo/p/3681296.html ---Ajax基础学习 http:/ ...
随机推荐
- 【转】HTTPS系列干货(一):HTTPS 原理详解
HTTPS系列干货(一):HTTPS 原理详解 前言 HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer),其实 HTTPS 并 ...
- [总结] min-25筛
再不写总结我又会忘掉啊啊啊啊啊啊啊啊啊 这个\(min-25\)筛主要用来求一个积性函数的前缀和,就像这样\[\sum_{i=1}^n f(i)\] 不过这个积性函数要满足两个条件:质数\(p\)的函 ...
- 31全志r58平台Android4.4.2下打开USB摄像头
31全志r58平台Android4.4.2下打开USB摄像头 2018/10/26 16:00 版本:V1.0 开发板:SC5806 1.系统编译:(略) 2.需要修改的文件: W:\r58_andr ...
- GIT SSH免登录密码实现更新(git pull)、推送(git push)操作
一.使用场景 现在有两台服务器A和B,在A服务器上搭建有git版本代码仓库,现要实现B服务器SSH免密码登录A服务器,并能够从A服务器拉取.推送代码! 二.操作步骤 1.在B服务器项目根目录下执行以 ...
- BZOJ 2539: [Ctsc2000]丘比特的烦恼
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 695 Solved: 260[Submit][Status][Discuss] Description ...
- KMP算法入门讲解
字符串匹配问题.假设文本是一个长度为$n$的字符串$T$,模板是一个长度为$m$的字符串$P$,且$m\leq n$.需要求出模板在文本中的所有匹配点$i$,即满足$T[i]=P[0],T[I+1]= ...
- pbr 5.2.1需使用中科大的源,豆瓣的不行
-bash-4.2$ .tox/tempest/bin/pip install pbr==5.2.1DEPRECATION: Python 2.7 will reach the end of its ...
- 什么是静态代码块?java中如何使用空参构造方法自动生成不同名字的对象,使用非静态的属性和静态属性有什么区别,原因是什么?如何理解static关键字
静态代码块?类加载就执行,最先执行 class demo{ static int num; static{ num=10; num*=3; System.out.println("haha& ...
- 解决vs 编译的bug“请检查是否是磁盘空间不足、路径无效或权限不够”
昨晚用vs编译遇到一个问题,编译一半发现硬盘没空间,一直重启vs,重启电脑, 删除pdb文件都没用,之后尝试重新生成解决方案,就解决了.这个是vs的一个bug
- JavaScript的基础知识
1,标识符 标识符是程序中常量或变量命名的一种术语称呼,并不是所有的字符组成都是一个合法的标识符,规范如下: 标识符的组成部分可以是字母,数字,下划线或美元($)符号 标识符开头是字母,下划线或美元( ...