Netty网络编程实战之搭建Netty服务器

 更新时间:2022年10月10日 10:17:06   作者:哪 吒  
Netty是JBOSS开源的一款NIO网络编程框架,可用于快速开发网络的应用。Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发高性能的服务端和客户端。本文将详细说说如何搭建Netty服务器,需要的可以参考一下

一、Netty是什么

Netty是JBOSS开源的一款NIO网络编程框架,可用于快速开发网络的应用。Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发高性能的服务端和客户端。可以极大的简化基于TCP、UDP等协议的网络服务。并且Netty对于各种传输类型(阻塞或非阻塞式的socket)、通信方式(HTTP或websocket)都提供了统一的API接口,提供了灵活的可扩展性,高度可自定义的线程模型(多线程、线程池等),支持使用无连接的数据报UDP进行通信,具有高吞吐量、低延迟、资源消耗低、最低限度的内存复制等特性。除了优越的性能外,Netty还支持SSL/TLS和StartTLS等加密传输协议,保证了数据传输的安全性。

在实际使用时,Netty可以作为Socket编程的中间件;也可以和Protobuf技术结合使用,实现一个RPC框架,实现远程过程调用;也可以作为一个websocket的长链接服务器,实现客户端和服务端的长连接通信。

二、Hello Netty

使用Netty作为一个Web服务器,用于接收用户请求并给出响应。

Netty程序一般都是按套路来写,依次编写主程序类、自定义初始化器、自定义处理器。

1、主程序类MyNettyServerTest

通过ServerBootstrap注册serverGroup和clientGroup两个事件循环组,其中serverGroup用于获取客户端连接,clientGroup用于处理客户端连接,类似于常见的Master-Slave结构。

2、初始化器MyNettyServerInitializer

继承Netty提供的初始化器ChannelInitializer。

Netty封装了各种各样的内置处理器,用于实现各种功能。并且ChannelInitializer的initChannel()方法会在某一个连接注册到Channel后立即被触发调用。因此,可以根据业务需求,在initChannel()中添加若干个Netty内置处理器,利用Netty强大的类库直接处理大部分业务。最后再在initChannel()中添加一个自定义处理器,用于实现特定业务的具体功能。

3、自定义处理器MyNettyServerHandler

继承SimpleChannelInboundHandler,该父类的channelRead0()方法可以接收客户端的所有请求,并作出响应,输出“Hello Netty”。

简单讲,Netty程序就是通过主程序类关联自定义初始化器,然后在初始化器中加入Netty内置处理器和自定义处理器,最后在自定义处理器中编写处理特定需求的业务代码。

三、代码实例

1、maven中加入netty-all

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.68.Final</version>
</dependency>

2、主程序类MyNettyServerTest

package com.guor.demo.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 主程序类
 */
public class MyNettyServerTest {
    public static void main(String[] args) throws InterruptedException {
        /**
         * EventLoopGroup:事件循环组,是一个线程池,也是一个死循环,用于不断地接收用户请求;
         * serverGroup:用户监听及建立连接,并把每一个连接抽象为一个channel,最后再将连接交给clientGroup处理;
         * clientGroup:真正的处理连接
         */
        EventLoopGroup serverGroup = new NioEventLoopGroup();
        EventLoopGroup clientGroup = new NioEventLoopGroup();
        try {
            // 服务端启动时的初始化操作
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // 1、将serverGroup和clientGroup注册到服务端的Channel上;
            // 2、注册一个服务端的初始化器MyNettyServerInitializer;
            // 3、该初始化器中的initChannel()方法会在连接被注册到Channel后立刻执行;
            // 5、最后将端口号绑定到8080;
            ChannelFuture channelFuture = serverBootstrap.group(serverGroup, clientGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new MyNettyServerInitializer()).bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        }catch (Exception e){
            System.out.println(e);
        }finally {
            serverGroup.shutdownGracefully();
            clientGroup.shutdownGracefully();
        }
    }
}

3、初始化器MyNettyServerInitializer

package com.guor.demo.netty;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;

/**
 * 初始化器
 */
public class MyNettyServerInitializer extends ChannelInitializer<SocketChannel> {

    // 连接被注册到Channel后,立刻执行此方法
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        // 加入netty提供的处理器
        pipeline.addLast("HttpServerCodec",new HttpServerCodec());
        // 增加自定义处理器MyNettyServerHandler,用于实际处理请求,并给出响应
        pipeline.addLast("MyNettyServerHandler",new MyNettyServerHandler());
    }
}

4、自定义处理器MyNettyServerHandler

package com.guor.demo.netty;

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;

/**
 * 自定义处理器
 * Inbound代表"进入"的请求
 */
public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        // 定义响应的内容
        ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8);
        DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
        defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
        byteBuf.readableBytes();
        // 等响应返回给客户端
        channelHandlerContext.writeAndFlush(defaultFullHttpResponse);
    }
}

5、通过curl http://localhost:8080访问Netty服务

此时,可能会提示curl不是内部或外部命令,如何解决?

四、curl不是内部或外部命令

1、下载curl for 64-bit

https://curl.se/windows/

2、将zip解压到文件夹

3、在环境变量中配置

五、重写SimpleChannelInboundHandler中一些重要的回调方法

1、重写回调方法

package com.guor.demo.netty;

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;

/**
 * 自定义处理器
 * Inbound代表"进入"的请求
 */
public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        // 定义响应的内容
        ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8);
        DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
        defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
        byteBuf.readableBytes();
        // 等响应返回给客户端
        channelHandlerContext.writeAndFlush(defaultFullHttpResponse);
    }

    /**
     * 增加新处理器时,触发此方法
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception{
        System.out.println("1、handlerAdded、增加了新的处理器");
        super.handlerAdded(ctx);
    }

    /**
     * 当通道被注册到一个事件循环组EventLoop上时,触发此方法
     */
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
        System.out.println("2、channelRegistered、通道被注册");
        super.channelRegistered(ctx);
    }

    /**
     * 当远端处于活跃状态时(连接到了某个远端,可以收发数据),执行此方法
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception{
        System.out.println("3、channelActive、通道连接到了远端,处于活跃状态");
        super.channelActive(ctx);
    }

    /**
     * 当通道处于非活跃状态时(与远端断开了连接),执行此方法
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception{
        System.out.println("4、channelInactive、通道远端断开了连接,处于非活跃状态");
        super.channelInactive(ctx);
    }

    /**
     * 当通道被取消了注册时,执行此方法
     */
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{
        System.out.println("5、channelUnregistered、通道被取消了注册");
        super.channelUnregistered(ctx);
    }

    /**
     * 当程序发生异常,执行此方法
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable e) throws Exception{
        System.out.println("6、exceptionCaught、程序发生了异常");
        e.printStackTrace();
        ctx.close();
    }
}

2、通过curl http://localhost:8080访问Netty服务

3、控制台输出

4、ctrl + c停止访问

以上就是Netty网络编程实战之搭建Netty服务器的详细内容,更多关于搭建Netty服务器的资料请关注脚本之家其它相关文章!

相关文章

  • Java对象为null的问题解决

    Java对象为null的问题解决

    如果一个对象为空,但是此时我们调用它的方法,就会遇到NullPointerException问题,本文主要介绍了Java对象为null的问题解决,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • Springboot教程之如何设置springboot热重启

    Springboot教程之如何设置springboot热重启

    这篇文章主要介绍了Springboot教程之如何设置springboot热重启,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 类似Object监视器方法的Condition接口(详解)

    类似Object监视器方法的Condition接口(详解)

    下面小编就为大家带来一篇类似Object监视器方法的Condition接口(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • java服务器的简单实现过程记录

    java服务器的简单实现过程记录

    在线浏览网页离不开服务器,用户发出请求request,服务器做出响应response,提供给用户需要的页面,这篇文章主要给大家介绍了关于java服务器简单实现的相关资料,需要的朋友可以参考下
    2021-11-11
  • Hibernate映射解析之关联映射详解

    Hibernate映射解析之关联映射详解

    所谓关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用。下面这篇文章详细的给大家介绍了Hibernate映射解析之关联映射的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-02-02
  • 如何解决项目中java heap space的问题

    如何解决项目中java heap space的问题

    这篇文章主要介绍了如何解决项目中java heap space的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • java中struts2实现文件上传下载功能

    java中struts2实现文件上传下载功能

    这篇文章主要介绍了java中struts2实现文件上传下载功能的方法,以实例形式分析了struts2文件上传下载功能的实现技巧与相关问题,具有一定的参考借鉴价值,需要的朋友可以参考下
    2016-05-05
  • SpringBoot @ControllerAdvice 拦截异常并统一处理

    SpringBoot @ControllerAdvice 拦截异常并统一处理

    这篇文章主要介绍了SpringBoot @ControllerAdvice 拦截异常并统一处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java字符串转驼峰格式的方法

    Java字符串转驼峰格式的方法

    在开发场景中,我们会遇到一些涉及字符串的转化,本文主要介绍了Java字符串转驼峰格式的方法,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Java源码解析之ClassLoader

    Java源码解析之ClassLoader

    在看系统启动的流程中看到了ClassLoader使用,重新温故下ClassLoader流程和原理,文中有非常详细的代码示例,对正在学习java的小伙伴们很有帮助,需要的朋友可以参考下
    2021-05-05

最新评论