时间:2018年04月11日星期三
说明:本文部分内容均来自慕课网。@慕课网:https://www.imooc.com
教学源码:https://github.com/zccodere/s...
学习源码:https://github.com/zccodere/s...

第一章:课程介绍

1-1 课程介绍

什么是Netty

  • 高性能、事件驱动、异步非阻塞的IO Java开源框架
  • 基于NIO的客户端,服务端编程框架
  • 非常可靠的稳定性和伸缩性

Netty使用场景

  • 高性能领域:游戏、大数据、分布式计算
  • 多线程并发领域:多线程模型、主从多线程模型
  • 异步通信领域:异步非阻塞,主动获取或通过通知机制来得到结果

课程提纲

  • IO通信:BIO、伪异步IO、NIO、AIO通信
  • Netty入门:原生NIO的缺陷、Netty的优势
  • WebSocket入门:什么是WebSocket、如何建立连接、生命周期及关闭
  • Netty实现WebSocket通信案例

课程要求

  • 有一定的Java基础
  • 有一定的IO编程基础
  • 了解Java的BIO、伪异步IO、NIO和AIO

第二章:IO通信

2-1 IO通信

BIO通信

  • 一个线程负责连接
  • 一请求一应答
  • 缺乏弹性伸缩能力

BIO通信模型

伪异步IO通信

  • 线程池负责连接
  • M请求N应答
  • 线程池阻塞

伪异步IO通信模型

NIO通信

  • 缓冲区Buffer
  • 通道Channel
  • 多路复用器Selector

AIO通信

  • 连接注册读写事件和回调函数
  • 读写方法异步
  • 主动通知程序

四种IO对比

第三章:Netty入门

3-1 Netty入门

原生NIO的缺陷

  • 类库和API繁杂
  • 入门门槛高
  • 工作量和难度大
  • JDK NIO存在BUG

Netty的优势

  • API使用简单,定制能力强,可以通过ChannelHandler对框架进行灵活的扩展
  • 入门门槛低,功能强大,预制了多种编解码功能,支持多种主流协议
  • 性能高,通过与其他的业界主流的NIO框架对比,Netty的综合性能最优
  • Netty比较成熟稳定,Netty修复了JDK NIO所有发现的BUG

第四章:WebSocket入门

4-1 WebSocket入门

什么是WebSocket

  • H5协议规范:H5提出的协议规范
  • 握手机制:使客户端与服务器能够建立类似TCP的连接,方便通信
  • 解决客户端与服务端实时通信而产生的技术:基于TCP的协议

WebSocket的优点

  • 节省通信开销:以前使用轮询,开销较大
  • 服务器主动传送数据给客户端:任意时刻,相互传送数据
  • 实时通信:可以彼此相互推送信息

WebSocket建立连接

  • 客户端发起握手请求
  • 服务器响应请求
  • 连接建立

WebSocket生命周期

  • 打开事件:发生新的连接时调用、在端点上建立连接时且在任何事件之前
  • 消息事件:接收WebSocket对话中,另一端发送的消息
  • 错误事件:在进行连接或端点发生错误时产生
  • 关闭事件:表示WebSocket端点的连接关闭

WebSocket关闭连接

  • 服务器关闭底层TCP连接
  • 客户端发起TCP Close

第五章:通信案例

5-1 通信案例

基于Netty实现WebSocket通信案例

功能介绍

  • Netty开发服务端
  • Html实现客户端
  • 实现服务端与客户端的实时交互

代码编写

1.创建名为netty-websocket的maven工程pom如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.myimooc</groupId><artifactId>netty-websocket</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>5.0.0.Alpha1</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build></project>

2.编写NettyConfig类

package com.myimooc.netty.websocket;import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;/*** <br>* 标题: Netty 全局配置类<br>* 描述: 存储整个工程的全局配置<br>** @author zc* @date 2018/04/11*/
public class NettyConfig {/*** 存储每一个客户端接入进来时的 Channel*/public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);}

3.编写MyWebSocketHandler类

package com.myimooc.netty.websocket;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.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;import java.util.Date;/*** <br>* 标题: 处理客户端WebSocket请求的核心业务处理类<br>* 描述: 接收/处理/响应 客户端websocket请求的核心业务处理类<br>** @author zc* @date 2018/04/11*/
public class MyWebSocketHandler extends SimpleChannelInboundHandler<Object> {private WebSocketServerHandshaker handshaker;private static final String WEB_SOCKET_URL = "ws://localhost:8888/websocket";/*** 服务端处理客户端websocket请求的核心方法*/@Overrideprotected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {if (msg instanceof FullHttpRequest) {// 处理客户端向服务端发起http握手请求的业务FullHttpRequest request = (FullHttpRequest) msg;this.handHttpRequest(ctx, request);} else if (msg instanceof WebSocketFrame) {// 处理websocket连接的业务WebSocketFrame frame = (WebSocketFrame) msg;this.handWebSocketFrame(ctx, frame);}}/*** 处理客户端与服务端之前的websocket业务*/private void handWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {if (frame instanceof CloseWebSocketFrame){// 如果是关闭websocket的指令handshaker.close(ctx.channel(),(CloseWebSocketFrame)frame.retain());}if (frame instanceof PingWebSocketFrame){// 如果是ping消息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 request) {if (!request.getDecoderResult().isSuccess() || !("websocket").equals(request.headers().get("Upgrade"))) {// 不是websocket握手请求时this.sendHttpResponse(ctx, request, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));return;}WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(WEB_SOCKET_URL, null, false);handshaker = wsFactory.newHandshaker(request);if (handshaker == null) {WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());} else {handshaker.handshake(ctx.channel(), request);}}/*** 服务端向客户端响应消息*/private void sendHttpResponse(ChannelHandlerContext ctc, FullHttpMessage request, DefaultFullHttpResponse response) {if (response.getStatus().code() != 200) {ByteBuf buf = Unpooled.copiedBuffer(response.getStatus().toString(), CharsetUtil.UTF_8);response.content().writeBytes(buf);buf.release();}// 服务端向客户端发送数据ChannelFuture future = ctc.channel().writeAndFlush(response);if (response.getStatus().code() != 200) {future.addListener(ChannelFutureListener.CLOSE);}}/*** 工程出现异常时调用*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}/*** 客户端与服务端创建连接时调用*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {NettyConfig.group.add(ctx.channel());System.out.println("客户端与服务端连接开启...");}/*** 客户端与服务端断开连接时调用*/@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {NettyConfig.group.remove(ctx.channel());System.out.println("客户端与服务端连接关闭...");}/*** 服务端接收客户端发送过来的数据结束之后调用*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.flush();}
}

4.编写MyWebSocketChannelHandler类

package com.myimooc.netty.websocket;import io.netty.channel.ChannelHandler;
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;/*** <br>* 标题: 初始化连接时的各个组件<br>* 描述: 初始化连接时的各个组件<br>** @author zc* @date 2018/04/11*/
public class MyWebSocketChannelHandler extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// 将请求和应答消息解码为HTTP消息ch.pipeline().addLast("http-codec",new HttpServerCodec());// 将HTTP消息的多个部分合成一条完整的HTTP消息ch.pipeline().addLast("aggregator",new HttpObjectAggregator(65536));// 向客户端发送HTML5文件ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());ch.pipeline().addLast("handler",new MyWebSocketHandler());}
}

5.编写AppStart类

package com.myimooc.netty.websocket;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;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;/*** <br>* 标题: 程序入口<br>* 描述: 启动应用<br>** @author zc* @date 2018/04/11*/
public class AppStart {public static void main(String[] args) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workGroup = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup,workGroup);serverBootstrap.channel(NioServerSocketChannel.class);serverBootstrap.childHandler(new MyWebSocketChannelHandler());System.out.println("服务端开启等待客户端连接...");Channel channel = serverBootstrap.bind(8888).sync().channel();channel.closeFuture().sync();}catch (Exception e){e.printStackTrace();}finally {// 优雅的退出程序bossGroup.shutdownGracefully();workGroup.shutdownGracefully();}}}

6.编写websocket.html

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta http-equiv="content-type" content="text/html"/><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(msg) {if (!window.WebSocket) {return;}if (socket.readyState == WebSocket.OPEN) {socket.send(msg);} else {alert("WebSocket连接没有建立成功");}}</script></head>
<body><form onSubmit="return false;"><input type="text" name="msg" value=""/><br/><br/><input type="button" value="发送WebSocket请求消息" onclick="send(this.form.msg.value)"/><hr color="red"/><h2>客户端接收到服务端返回的应答消息</h2><textarea id="responseContent" style="width: 1024px;height: 300px"></textarea>
</form></body>
</html>

第六章:课程总结

6-1 课程总结

课程总结

  • 课程介绍
  • IO通信:四种IO通信
  • Netty入门:原生NIO的缺点,Netty的优点
  • WebSocket入门:WebSocket的优点,如何使用
  • 通信案例:Netty实现WebSocket通信案例

慕课网_《Netty入门之WebSocket初体验》学习总结相关推荐

  1. 慕课网_《微信授权登录》学习总结

    时间:2017年08月12日星期六 说明:本文部分内容均来自慕课网.@慕课网:http://www.imooc.com 教学源码:无 学习源码:https://github.com/zccodere/ ...

  2. 微信授权登录(微信订阅号使用测试账号)

    1.微信授权登录: 微信公众号测试登录: 准备: 1.1 花生壳! 下载地址:http://hsk.oray.com/download/ 1.2 微信公众号:https://mp.weixin.qq. ...

  3. 硅谷课堂 12_公众号消息和微信授权登录

    硅谷课堂第十二天-公众号消息和微信授权登录 文章目录 硅谷课堂第十二天-公众号消息和微信授权登录 一.公众号普通消息 1.实现目标 2.消息接入 2.1.公众号服务器配置 2.2.验证来自微信服务器消 ...

  4. uni app和php开发微信登录代码,uniapp如何实现微信授权登录

    uniapp实现微信授权登录的方法:首先获取对应的appid和appsecret:然后在uniapp项目的manifest.json中进行APP SDK配置和模块权限配置.最后实现编码. 本教程操作环 ...

  5. thinkphp 微信授权登录 以及微信实现分享

    <?php namespace app\wechat\controller; use think\Controller; use think\Request; /** * 微信授权登录类 * U ...

  6. code换取微信openid_微信授权登录开发的两种方式

    本文主要针对微信公众号(公众平台的开发) 首先理解一个概念:OAuth: OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表), ...

  7. Java版本微信授权登录(升级版)

    前面写了一遍文章<Java版本微信授权登录(测试版)>,可以当做入门的基础文章,这里继续做一点深入,主要解决的是,如何在本地开发中微信授权以后跳转到本地启动的项目中. 我们知道了微信公众平 ...

  8. android友盟微信授权登录清除,【转载】Android友盟SDK微信授权登录接入

    微信授权登录接入需要先到微信开放平台申请好应用的APPID,交纳300大洋费用得到授权登录权限后才能使用,此处不再赘述. 接入的两种方式 -- 微信SDK接入:使用微信官方SDK接入,需要分" ...

  9. uniapp开发h5微信授权登录(详细教程)

    uniapp开发h5微信授权登录 文章目录 uniapp开发h5微信授权登录 前言 一.前期准备--申请测试账号 二.正式开发--前端代码 三.打包发布 总结 前言 我也是第一次做h5授权微信登录,网 ...

  10. springboot微信授权登录

    水平有限!实现方法直接找的网上的以为大神所编写的api来实现,这里主要是记录一下自己实现的过程.具体方法请参考网址:https://github.com/liyiorg/weixin-popular, ...

最新文章

  1. android AIDL服务
  2. 【数据分析】33个热门数据分析软件,你都用过哪些?
  3. c语言如何让数组的两个数据调换位置_浅论数据结构
  4. c语言 两条线段位置,C++/STL实现判断平面内两条线段的位置关系代码示例
  5. Android特效 五种Toast具体解释
  6. [转载] Python中TFTP的理解
  7. caffeine 时间轮的实现
  8. pythonstdin_如何在Python中执行将数据写入stdin的进程?
  9. 推荐一个 Java 实体映射工具 MapStruct 1
  10. cmd查看IP地址指令
  11. RGB颜色 取色器/拾色器 颜色混搭
  12. 三星帝国的风险:四大业务同荣同损
  13. fgo服务器维护2018.123,FGO9月30日更新维护公告
  14. html5使用table制作表单
  15. java和python爬虫那个好_java和python在爬虫方面的优势和劣势是什么?
  16. c++ 计算多图形面积
  17. 计算机内存小怎么改大,电脑内存太小的优化方法步骤
  18. upgrade-insecure-requests强制转http为https
  19. App UI交互与视觉设计
  20. Houdini 中DOP CHOP SHOP SOP VOP是什么?

热门文章

  1. atitit. 解决org.hibernate.SessionException Session is closed
  2. paip.代码生成器数据源格式最佳实践
  3. 并不是部所有市场都类似:评估 Marketplace 的 10 个特征
  4. (转)如何看待美国监管机构要求文艺复兴基金提交源码?
  5. 不确定性原理的前世今生 · 数学篇(完)
  6. PolarDB-X 一致性共识协议 (X-Paxos)
  7. 非常有意思的35句话
  8. 【图像加密】基于matlab GUI彩色图像加密解密(带面板)【含Matlab源码 1231期】
  9. 【答题卡识别】基于matlab形态学答题卡识别【含Matlab源码 1135期】
  10. 【语音去噪】基于matlab GUI傅立叶变换语音降噪混频【含Matlab源码 297期】