@toc

Netty是一款基于NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比于BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高。

1、Netty为什么传输快

Netty的传输快其实也是依赖了NIO的一个特性——零拷贝。我们知道,Java的内存有堆内存、栈内存和字符串常量池等等,其中堆内存是占用内存空间最大的一块,也是Java对象存放的地方,一般我们的数据如果需要从IO读取到堆内存,中间需要经过Socket缓冲区,也就是说一个数据会被拷贝两次才能到达他的的终点,如果数据量大,就会造成不必要的资源浪费。

Netty针对这种情况,使用了NIO中的另一大特性——零拷贝,当他需要接收数据的时候,他会在堆内存之外开辟一块内存,数据就直接从IO读到了那块内存中去,在netty里面通过ByteBuf可以直接对这些数据进行直接操作,从而加快了传输速度。

2、Netty和Tomcat有什么区别?

Netty和Tomcat最大的区别就在于通信协议,Tomcat是基于Http协议的,他的实质是一个基于http协议的web容器,但是Netty不一样,他能通过编程自定义各种协议,因为netty能够通过codec自己来编码/解码字节流,完成类似redis访问的功能,这就是netty和tomcat最大的不同。

3、Netty-websocket-spring-boot-starter

这是个开源的框架。通过它,我们可以像spring-boot-starter-websocket一样使用注解进行开发,只需关注需要的事件(如OnMessage)。并且底层是使用Netty,netty-websocket-spring-boot-starter其他配置和spring-boot-starter-websocket完全一样,当需要调参的时候只需要修改配置参数即可,无需过多的关心handler的设置。

Maven配置:

<!-- 注释掉默认的websocket starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>-->
<!-- 启用Netty https://mvnrepository.com/artifact/org.yeauty/netty-websocket-spring-boot-starter -->
<dependency>
<groupId>org.yeauty</groupId>
<artifactId>netty-websocket-spring-boot-starter</artifactId>
<version>0.7.6</version>
</dependency>

new一个ServerEndpointExporter对象,交给Spring IOC容器,表示要开启WebSocket功能,样例如下:

@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

在端点类上加上@ServerEndpoint、@Component注解,并在相应的方法上加上@OnOpen、@OnClose、@OnError、@OnMessage、@OnBinary、OnEvent注解,样例如下:

@ServerEndpoint
@Component
public class MyWebSocket { @OnOpen
public void onOpen(Session session, HttpHeaders headers, ParameterMap parameterMap) throws IOException {
System.out.println("new connection"); String paramValue = parameterMap.getParameter("paramKey");
System.out.println(paramValue);
} @OnClose
public void onClose(Session session) throws IOException {
System.out.println("one connection closed");
} @OnError
public void onError(Session session, Throwable throwable) {
throwable.printStackTrace();
} @OnMessage
public void onMessage(Session session, String message) {
System.out.println(message);
session.sendText("Hello Netty!");
} @OnBinary
public void onBinary(Session session, byte[] bytes) {
for (byte b : bytes) {
System.out.println(b);
}
session.sendBinary(bytes);
} @OnEvent
public void onEvent(Session session, Object evt) {
if (evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
switch (idleStateEvent.state()) {
case READER_IDLE:
System.out.println("read idle");
break;
case WRITER_IDLE:
System.out.println("write idle");
break;
case ALL_IDLE:
System.out.println("all idle");
break;
default:
break;
}
}
} }

打开WebSocket客户端,连接到ws://127.0.0.1:80

4、注解

4.1 @ServerEndpoint

当ServerEndpointExporter类通过Spring配置进行声明并被使用,它将会去扫描带有@ServerEndpoint注解的类

被注解的类将被注册成为一个WebSocket端点

所有的配置项都在这个注解的属性中 ( 如:@ServerEndpoint("/ws") )

4.2 @OnOpen

当有新的WebSocket连接进入时,对该方法进行回调

注入参数的类型:Session、HttpHeaders、ParameterMap

4.3 @OnClose

当有WebSocket连接关闭时,对该方法进行回调

注入参数的类型:Session

4.4 @OnError

当有WebSocket抛出异常时,对该方法进行回调

注入参数的类型:Session、Throwable

4.5 @OnMessage

当接收到字符串消息时,对该方法进行回调

注入参数的类型:Session、String

4.6 @OnBinary

当接收到二进制消息时,对该方法进行回调

注入参数的类型:Session、byte[]

4.7 @OnEvent

当接收到Netty的事件时,对该方法进行回调

注入参数的类型:Session、Object

5、配置

所有的配置项都在这个注解的属性中

6、通过application.properties进行配置

对注解中的prefix进行设置后,即可在application.properties中进行配置。如下:

  • 首先在ServerEndpoint注解中设置prefix的值
@ServerEndpoint(prefix = "netty-websocket")
@Component
public class MyWebSocket {
...
}
  • 接下来即可在application.properties中配置
netty-websocket.host=0.0.0.0
netty-websocket.path=/
netty-websocket.port=80

application.properties中的key与注解@ServerEndpoint中属性的对应关系如下:

7、自定义Favicon

配置favicon的方式与spring-boot中完全一致。只需将favicon.ico文件放到classpath的根目录下即可。如下:

src/
+- main/
+- java/
| + <source code>
+- resources/
+- favicon.ico

8、自定义错误页面

配置自定义错误页面的方式与spring-boot中完全一致。你可以添加一个 /public/error 目录,错误页面将会是该目录下的静态页面,错误页面的文件名必须是准确的错误状态或者是一串掩码,如下:

src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
| +- 5xx.html
+- <other public assets>

9、多端点服务

  • 在快速启动的基础上,在多个需要成为端点的类上使用@ServerEndpoint、@Component注解即可
  • 可通过ServerEndpointExporter.getInetSocketAddressSet()获取所有端点的地址
  • 当地址不同时(即host不同或port不同),使用不同的ServerBootstrap实例
  • 当地址相同,路径(path)不同时,使用同一个ServerBootstrap实例
  • 当多个端点服务的port为0时,将使用同一个随机的端口号
  • 当多个端点的port和path相同时,host不能设为"0.0.0.0",因为"0.0.0.0"意味着绑定所有的host

(二)基于Netty的高性能Websocket服务器(netty-websocket-spring-boot)的更多相关文章

  1. Netty实现高性能RPC服务器优化篇之消息序列化

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

  2. Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上

    前言 诞生及优势 MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,现为Cirrus Link)于1999年开发,用于监测穿越沙漠的石油管道.目标 ...

  3. Netty实现高性能IOT服务器(Groza)之精尽代码篇中

    运行环境: JDK 8+ Maven 3.0+ Redis 技术栈: SpringBoot 2.0+ Redis (Lettuce客户端,RedisTemplate模板方法) Netty 4.1+ M ...

  4. Netty实现高性能RPC服务器

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

  5. 曹工杂谈:Linux服务器上,Spring Boot 原地修改 jar 包配置文件/替换class文件,免去重复上传的麻烦

    一.前言 相信很多同学有这样的需求,现在很多公司都有多地的研发中心,经常需要跨地区部署,比如,博主人在成都,但是服务器是北京的.一般城市间网络都不怎么好,上传一个几十兆的jar包那是真的慢,别说现在微 ...

  6. IDEA连接远程服务器Docker部署Spring Boot项目

    开始前的准备工作 拥有一台云服务器,我的是腾讯云服务器(CentOS7) 腾讯云服务器安装Docker,我的版本是Docker 19.03.9,关于安装和配置镜像加速器可以查阅我的另一篇博文:http ...

  7. 头秃了,二十三张图带你从源码了解Spring Boot 的启动流程~

    持续原创输出,点击上方蓝字关注我 目录 前言 源码版本 从哪入手? 源码如何切分? 如何创建SpringApplication? 设置应用类型 设置初始化器(Initializer) 设置监听器(Li ...

  8. 基于Centos7.4搭建prometheus+grafana+altertManger监控Spring Boot微服务(docker版)

    目的:给我们项目的微服务应用都加上监控告警.在这之前你需要将 Spring Boot Actuator引入 本章主要介绍 如何集成监控告警系统Prometheus 和图形化界面Grafana 如何自定 ...

  9. 基于Servlet体系的HTTP请求代理转发Spring Boot组件

    背景概述 两个项目组原本都是各自负责两个产品线(产品A.产品B),由于公司业务的发展,目前需要将两个产品合并成一个大产品(功能整合,部分做取舍,最终产出产品C),前后端代码必然也需要整合,包括两个产品 ...

  10. 浅析websocket的基本应用spring boot + vue +C# + WPF

    1.基本概念 首先websocket是基于H5的一种通信.在网页中如果定时获取服务器端的实时数据,我们常采用long poll 和ajax轮询的方式.但是在轮询过程中,由于根本没有新数据的改变,而造成 ...

随机推荐

  1. 初探JAVA内部类细节一

    定义: 可以将一个类的定义放在另一个类的内部 这就是内部类.--摘自java编程思想 一般实现方式: public class SimpleInnerClass { class Content { p ...

  2. Redis基础篇(八)数据分片

    现在有一个场景:要用Redis保存5000万个键值对,每个键值对大约是512B,要怎么部署Redis服务呢? 第一个方案,也是最容易想到的,需要保存5000万个键值对,每个键值对约为512B,一共需要 ...

  3. python之json、pickle模块

    一.json模块 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候, ...

  4. WPF 关于拖拽打开文件的注意事项

    由于开发需求,需要开发一个类似Win图片浏览的工具 当然也涉及到了拖拽打开的需求 按照固有思路: <Grid x:Name="grid1" AllowDrop="T ...

  5. springboot源码解析-管中窥豹系列之排序(五)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  6. Java菜鸟在IP问题踩坑了

    之前有做过获取客户端公网IP的项目 一般都是 正常的request.getRemoteAddr 或者request.getRemoteHost 可获取到客户端的公网IP, 或者项目部署在有nginx代 ...

  7. RabbitMQ常用的几种消息模型

    第一种模型(HelloWorld) 上图来自官方文档 P代表生产者用来生产消息,发送给消费者C,中间的共色部分代表消息队列,用来缓存消息. 首先导入依赖 <dependency> < ...

  8. selenium自动化 | 通过获取cookies登录

    >>>登录百度<<<#获取登录成功后的cookies def get_cookies(): driver.get(bd_url) driver.implicitly ...

  9. 十三:SQL注入之MYSQL注入

    MYSQL注入中首先要明确当前注入点权限,高权限注入时有更多的攻击手法,有的能直接进行getshell操作,其中也会遇到很多的阻碍,相关防御手法也要明确,所谓知己知彼,百战不殆.作为安全开发工作者,攻 ...

  10. 【Docker】Docker启动停止重启 Redirecting to /bin/systemctl start docker.service

    [root@liuawen local]# docker -v Docker version 1.13.1, build cccb291/1.13.1 [root@liuawen local]# 启动 ...