文章目录

  • 一、概述
  • 1、简介
  • 2、特点
  • 3、Gradle
  • 4、demo

一、概述

1、简介

Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。

客户端向服务端发送一个http请求,验证之后建立长连接,控制层接收请求业务层进行业务处理,产生数据之后返回这是使用websocket建立长连接的一个流程,而netty的作用就是将http请求发送出来的这些数据根据协议的规范,抽取出事件,形成回调方法去处理。

Spark也是对于netty的一种封装,就像SparkStreaming处理数据流的流程这样的目的就是对于事件有着高效处理的功能。

java netty客户端发信息 netty服务端发消息给客户端_System

2、特点

设计

  1. 针对bio/nio指定了一个普通的api
  2. 基于灵活且可扩展的事件模型,可以清晰地分离关注点
  3. 高度可定制的线程模型 - 单线程,一个或多个线程池,如SEDA
  4. 真正的无连接数据报套接字支持(自3.1起)

使用

  1. 详细记录的Javadoc,用户指南和示例

性能

  1. 更高的吞吐量,更低的延迟
  2. 减少资源消耗
  3. 最小化不必要的内存复制

安全

  1. 完整的SSL\TLS和StartTLS支持

社区

  1. 发布时间早,且常更新

3、Gradle

Gradle类似于maven,区别是它更加灵活更加强大,但是和xml语言构建的maven不同,Gradle的语言是基于Groove的。

首先创建好依赖:

plugins {
    id 'java'
}

group 'com.gongda'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    implementation(
            'io.netty:netty-all:4.1.39.Final'
    )
}

4、demo

通过netty实现一个简单的小案例,简单讲解一下流程:

  1. 首先创建一个异步事件循环组,一个负责连接,一个负责之后的业务处理
  2. 服务端在启动之前首先要进行配置,可以自定义也可以用封装好的配置

但无论如何,配置的文件都是在连接成功之后针对管道的配置,所以需要继承基础的初始化父类。

java netty客户端发信息 netty服务端发消息给客户端_Netty_02


重写initChannel方法,创建管道拦截器配置

java netty客户端发信息 netty服务端发消息给客户端_java netty客户端发信息_03


创建内部封装好的配置

java netty客户端发信息 netty服务端发消息给客户端_System_04


也可以创建自定义的拦截器

java netty客户端发信息 netty服务端发消息给客户端_System_05

在拦截器内部自己定义要实现的功能:

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

import java.net.URI;

public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

        System.out.println(msg.getClass());
        System.out.println(ctx.channel().remoteAddress());
        Thread.sleep(8000);

        if (msg instanceof HttpRequest){

            HttpRequest httpRequest = (HttpRequest)msg;
            System.out.println("请求方法名" + httpRequest.method().name());

            URI uri = new URI(httpRequest.uri());
            if ("/favicon.ico".equals(uri.getPath())){
                System.out.println("请求favicon.ico");
                return;
            }

            ByteBuf context = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, context);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, context.readableBytes());

            ctx.writeAndFlush(response);
            ctx.channel().close();
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel Active");
        super.channelActive(ctx);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel Registered");
        super.channelRegistered(ctx);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handler Added");
        super.handlerAdded(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel Inactive");
        super.channelInactive(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel Unregistered");
        super.channelUnregistered(ctx);
    }
}
  1. Server端将自定义的初始化配置操作添加进来,绑定端口
  2. 结束之后进行回收

调用了一个HttpServletCodec,它是内部封装好的一个拦截器配置,作用十分强大,对于http请求进行编解码进行字节码的转换。

另外,还有一点需要注意Netty和SpringMVC甚至和SpringBoot都是有很大区别的,因为Netty所负责的业务功能,都被SpringBoot封装好了,就像域名匹配、端口转发,但是我们使用Netty的原因更多是为了并发,所以Netty是一个比较底层的框架,甚至没有端口映射、域名匹配的封装 。

  1. 创建一个客户端与服务端互通

Server端差不多在Client端要实现的就是连接,并且可以做到端口映射、现互通。
模型其实都是和Server端差不多的。

先创建线程模型,然后创建连接的配置:

java netty客户端发信息 netty服务端发消息给客户端_Netty_06


同样也需要一个客户端的初始化去做拦截器和服务端是一样的。

java netty客户端发信息 netty服务端发消息给客户端_java netty客户端发信息_07

控制器决定连接之后做什么:

public class MyClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress());
        System.out.println("client output" + msg);
        ctx.writeAndFlush("from Client" + LocalDateTime.now());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush("客户端");
    }
}

然后注意的是,我们要将之前的http请求的信息种类改成String的种类,并且在两个端的拦截器去除掉httpServerCodec的拦截,不然不会打印出信息的。