Netty 最简demo

Netty是什么

Netty到底是何方神圣?

用一句简单的话来说就是:Netty封装了JDK的NIO,让你用得更方便,不用再写一大堆复杂的代码了。

用官方正式的话来说就是:Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务端和客户端。

使用Netty而不使用JDK原生NIO的原因

1.使用JDK原生NIO需要了解太多概念,编程复杂,一不小心就Bug横飞。

2.Netty底层IO模型随意切换,而这一切只需要做微小的改动,改改参数,Netty可以直接从NIO模型变身为IO模型。

3.Netty自带的拆包/粘包、异常检测等机制让你从NIO的繁重细节中脱离出来,只需要关心业务逻辑即可。

4.Netty解决了JDK很多包括空轮询在内的Bug。

5.Netty底层对线程、Selector做了很多细小的优化,精心设计的Reactor线程模型可以做到非常高效的并发处理。

6.自带各种协议栈,让你处理任何一种通用协议都几乎不用亲自动手。

7.Netty社区活跃,遇到问题随时邮件列表或者Issue。

8.Netty已经历各大RPC框架、消息中间件、分布式通信中间件线上的广泛验证,健壮性无比强大。

引入Maven依赖

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.6.Final</version>
        </dependency>

服务端最简化代码

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;

import java.util.Date;

public class NettyClient {


    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
        // 引导器引导启动
        bootstrap.group(eventExecutors)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
        bootstrap
                .group(workerGroup) // 指定线程模型,驱动连接的数据读写
                .channel(NioSocketChannel.class) // 指定IO模型为NioSocketChannel,表示IO模型为NIO
                .handler(new ChannelInitializer<Channel>() { // 给引导类指定一个Handler,主要定义连接的业务处理逻辑
                    @Override
                    protected void initChannel(Channel channel) throws Exception {
                        channel.pipeline().addLast(new StringEncoder());
                    }
                });

        // 建立通道
        /*
         * 配置完线程模型、IO模型、业务处理逻辑之后,调用connect方法进行连接,
         * 可以看到connect方法有两个参数,第一个参数可以填写IP或者域名,第二个参数填写端口号。
         * 由于connect方法返回的是一个Future,也就是说这个方法是异步的,通过addListener方法可以监听连接是否成功,进而打印连接信息。
         */
        Channel channel = bootstrap.connect("127.0.0.1", 8000).channel();

        while (true) {
            channel.writeAndFlush(new Date() + " Hello world");
            Thread.sleep(2000);
        }

    }

}

客户端最简化代码

package com.xc.xcspringboot.test;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

public class NettyServer {

    public static void main(String[] args) {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        NioEventLoopGroup boosGroup = new NioEventLoopGroup(); // bossGroup表示监听端口,接收新连接的线程组
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(); // workerGroup表示处理每一个连接的数据读写的线程组

        NioEventLoopGroup boosGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap(); // 引导类ServerBootstrap,这个类将引导服务端的启动工作
        serverBootstrap
                .group(boosGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel ch) {
                .group(boosGroup, workerGroup) // .group(bossGroup,workerGroup)给引导类配置两大线程组
                .channel(NioServerSocketChannel.class) // 指定服务端的IO模型为NIO NioServerSocketChannel是对NIO类型连接的抽象
                .childHandler(new ChannelInitializer<NioSocketChannel>() { // childHandler()方法,给这个引导类创建一个ChannelInitializer,主要是定义后续每个连接的数据读写
                    protected void initChannel(NioSocketChannel ch) { // 泛型参数NioSocketChannel,这个类就是Netty对NIO类型连接的抽象
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                                System.out.println(msg);
                            }
                        });
                    }
                })
                /*
                 * 要启动一个Netty服务端,必须要指定三类属性,分别是线程模型、IO模型、连接读写处理逻辑。
                 * 有了这三者,之后再调用bind(8000),就可以在本地绑定一个8000端口启动服务端。
                 */
                .bind(8000);
    }

}

文章来源: 《跟闪电侠学Netty》-第2章 Netty是什么

以下是一个简单的Netty自定义协议的示例代码,该协议由消息头和消息体组成,消息头包含消息的长度信息,消息体包含具体的消息内容。 1. 定义消息类 ```java public class MyMessage { private int length; private String content; // getter and setter methods } ``` 2. 编写编解码器 ```java public class MyMessageCodec extends MessageToByteEncoder<MyMessage> { @Override protected void encode(ChannelHandlerContext ctx, MyMessage msg, ByteBuf out) throws Exception { byte[] contentBytes = msg.getContent().getBytes(CharsetUtil.UTF_8); out.writeInt(contentBytes.length); out.writeBytes(contentBytes); } } public class MyMessageDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (in.readableBytes() < 4) { return; } in.markReaderIndex(); int length = in.readInt(); if (in.readableBytes() < length) { in.resetReaderIndex(); return; } byte[] contentBytes = new byte[length]; in.readBytes(contentBytes); String content = new String(contentBytes, CharsetUtil.UTF_8); MyMessage message = new MyMessage(); message.setLength(length); message.setContent(content); out.add(message); } } ``` 3. 编写服务端和客户端代码 服务端代码: ```java public class MyServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new MyMessageDecoder()); pipeline.addLast(new MyServerHandler()); pipeline.addLast(new MyMessageCodec()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(8888).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } public class MyServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { MyMessage message = (MyMessage) msg; System.out.println("Server receive message: " + message.getContent()); message.setContent("Hello, " + message.getContent() + "!"); ctx.writeAndFlush(message); } } ``` 客户端代码: ```java public class MyClient { public static void main(String[] args) throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new MyMessageCodec()); pipeline.addLast(new MyMessageDecoder()); pipeline.addLast(new MyClientHandler()); } }); ChannelFuture f = b.connect("localhost", 8888).sync(); for (int i = 0; i < 10; i++) { MyMessage message = new MyMessage(); message.setContent("world-" + i); f.channel().writeAndFlush(message); Thread.sleep(1000); } f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } } public class MyClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { MyMessage message = (MyMessage) msg; System.out.println("Client receive message: " + message.getContent()); } } ``` 以上代码演示了如何使用Netty实现自定义协议,其中MyMessageCodec和MyMessageDecoder负责编解码,MyServer和MyServerHandler负责服务端逻辑,MyClient和MyClientHandler负责客户端逻辑。在本示例中,自定义协议包含消息头和消息体,消息头包含消息长度信息,消息体包含具体的消息内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值