Netty教程系列(一)——netty入门应答程序

朱雀 2022-06-13 04:45 459阅读 0赞

Netty简介

Netty是一个异步通信、事件驱动基于NIO编写的高性能高并发的java网络编程框架。下面通过一个简单的服务器应答程序来完成Netty的初步学习。

代码地址:https://gitee.com/ShiXiCheng/study_netty

Netty的编程例子——应答程序

设置开发环境

Jdk1.8

Mvn配置

  1. <dependencies>
  2. <dependency>
  3. <groupId>io.netty</groupId>
  4. <artifactId>netty-all</artifactId>
  5. <version>4.1.12.Final</version>
  6. </dependency>
  7. </dependencies>

应答服务器

一个Netty服务器主要有三个部分组成

l 服务器配置,配置端口、操作线程池等。

l 通道初始程序,传输的编解码格式、粘包处理、通道处理程序的调用。

l 实现通道处理程序,它包含业务逻辑,即实现服务器通道发生连接、读取信息等事件时的处理。

启动服务器

通过创建SerserBootstrap对象来启动服务器,然后配置对象的相关属性,如端口、线程模式、处理程序等。

  1. import io.netty.bootstrap.ServerBootstrap;
  2. import io.netty.channel.ChannelFuture;
  3. import io.netty.channel.EventLoopGroup;
  4. import io.netty.channel.nio.NioEventLoopGroup;
  5. import io.netty.channel.socket.nio.NioServerSocketChannel;
  6. public classHelloServer {
  7. private static final int protNumner= 7878;
  8. public static void main(String[] args) throws InterruptedException {
  9. // 事件循环组
  10. /*
  11. * Main函数开始的位置定义了两个工作线程,一个命名为WorkerGroup,另一个命名为BossGroup。
  12. * 都是实例化NioEventLoopGroup。这一点和3.x版本中基本思路是一致的。Worker线程用于管理线程为Boss线程服务。
  13. * EventLoopGroup,它是4.x版本提出来的一个新概念。类似于3.x版本中的线程。用于管理Channel连接的。
  14. * 在main函数的结尾就用到了EventLoopGroup提供的便捷的方法,shutdownGraceFully(),
  15. * 翻译为中文就是优雅的全部关闭。
  16. */
  17. EventLoopGroupbossGroup= newNioEventLoopGroup();
  18. EventLoopGroupworkerGroup= newNioEventLoopGroup();
  19. /* ServerBootstrap负责初始化netty服务器,并且开始监听端口的socket请求 */
  20. ServerBootstrapb = new ServerBootstrap();
  21. b.group(bossGroup, workerGroup);
  22. b.channel(NioServerSocketChannel.class);
  23. b.childHandler(newHelloServerInitializer());
  24. // 服务器绑定端口监听
  25. ChannelFuturef = b.bind(protNumner).sync();
  26. // 监听服务器关闭监听
  27. f.channel().closeFuture().sync();
  28. }
  29. }

通道的初始化程序

初始化程序可以加上编解码、消息分割(粘包)、业务处理程序等。这些设置都是通过ChannelPipeline.addLast()来实现的。

  1. import io.netty.channel.ChannelInitializer;
  2. import io.netty.channel.ChannelPipeline;
  3. import io.netty.channel.socket.SocketChannel;
  4. import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  5. import io.netty.handler.codec.Delimiters;
  6. import io.netty.handler.codec.string.StringDecoder;
  7. import io.netty.handler.codec.string.StringEncoder;
  8. public classHelloServerInitializer extends ChannelInitializer<SocketChannel> {
  9. @Override
  10. protected voidinitChannel(SocketChannel ch) throwsException {
  11. ChannelPipelinepipeline= ch.pipeline();
  12. // 以("\n")为结尾分割的解码器,最大帧长度为8192
  13. // Delimiter Based Frame Decoder 基于定界符的帧解码器
  14. // Delimiters.lineDelimiter()行分隔符
  15. // 这里使用时,会把换行符作为一个消息的分隔界限使用,即接收时,换行符前为一条消息
  16. pipeline.addLast("framer",newDelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  17. // 字符串解码和编码
  18. // encoder 编码器, decoder 解码器
  19. pipeline.addLast("decoder",newStringDecoder());
  20. pipeline.addLast("encoder",newStringEncoder());
  21. // 自己的逻辑Handler
  22. pipeline.addLast("handler",newHelloServerHandler());
  23. }
  24. }

通道的业务处理程序

处理程序是事件驱动的,用于监控服务器事件的产生,自定义事件的处理。

  1. import java.net.InetAddress;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.SimpleChannelInboundHandler;
  4. public classHelloServerHandler extends SimpleChannelInboundHandler<String> {
  5. @Override
  6. protected voidchannelRead0(ChannelHandlerContext ctx, String msg)throwsException {
  7. // 收到消息直接打印输出
  8. System.out.println(ctx.channel().remoteAddress()+ " Say : "+ msg);
  9. // 返回客户端信息 - 我已经接收到了你的消息
  10. // writeAndFlush写消息并发送
  11. ctx.writeAndFlush("received your message !\n");
  12. }
  13. // 当Channel变成活跃状态时被调用
  14. public voidchannelActive(ChannelHandlerContext ctx) throwsException {
  15. System.out.println("RamoteAddress : "+ ctx.channel().remoteAddress()+ " active !");
  16. ctx.writeAndFlush("welcome to "+ InetAddress.getLocalHost().getHostName() + " server.\n");
  17. super.channelActive(ctx);
  18. }
  19. }

SimpleChannelInboundHandler这里实现事件处理,ChannelRead0是读取数据事件,channelActive是通道连接事件。

除了以上事件,还有如下事件

void channelInactive(ChannelHandlerContextctx) 连接中断时,调用它

void userEventTriggered(ChannelHandlerContext ctx, Object evt) 如果触发了用户事件,将调用它。

void channelWritabilityChanged(ChannelHandlerContextctx) 一旦更改了{连接信道}的可写状态,就调用。您可以检查状态

void exceptionCaught(ChannelHandlerContextctx, Throwable cause) 如果抛出异常,将调用它。

在writeAndFlush后要接”\n”,pipeline设置的是通过换行符来分割信息。

编写应答程序客户端

一个客户端程序主要有三部分组成,与服务器类似

l 连接服务器,配置服务器的ip、端口,创建服务器连接通道对象,向服务器发送数据

l 通道初始程序,传输的解编码格式、粘包处理、通道处理程序的调用。

l 实现通道处理程序,它包含业务逻辑,即实现客户端通道发生连接、读取信息等事件时的处理。

连接服务器

Netty4通过Bootstrap来创建通道连接对象Channel,通过Channel的writeAndFlush来向服务器发送数据。

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. import io.netty.bootstrap.Bootstrap;
  5. import io.netty.channel.Channel;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.nio.NioSocketChannel;
  9. /**
  10. * netty客户端
  11. *
  12. * @author逝兮诚
  13. * @date 2017年6月26日下午5:37:23
  14. *
  15. */
  16. public classHelloClient {
  17. public static String host = "127.0.0.1";
  18. public static int port = 7878;
  19. public static void main(String[] args) throws IOException,InterruptedException {
  20. EventLoopGroupgroup= newNioEventLoopGroup();
  21. Bootstrapb = new Bootstrap();
  22. b.group(group).channel(NioSocketChannel.class).handler(newHelloClientInitializer());
  23. // 连接服务端
  24. Channelch = b.connect(host, port).sync().channel();
  25. // 控制台输入
  26. BufferedReaderin = new BufferedReader(newInputStreamReader(System.in));
  27. for (;;) {
  28. Stringline= in.readLine();
  29. if (line == null)
  30. continue;
  31. ch.writeAndFlush(line + "\r\n");
  32. }
  33. }
  34. }

通道的初始化设置程序

初始化设置程序同服务器一样,便不再过多累述。

  1. import io.netty.channel.ChannelInitializer;
  2. import io.netty.channel.ChannelPipeline;
  3. import io.netty.channel.socket.SocketChannel;
  4. import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  5. import io.netty.handler.codec.Delimiters;
  6. import io.netty.handler.codec.string.StringDecoder;
  7. import io.netty.handler.codec.string.StringEncoder;
  8. public classHelloClientInitializer extends ChannelInitializer<SocketChannel> {
  9. @Override
  10. protected voidinitChannel(SocketChannel ch) throwsException {
  11. ChannelPipelinepipeline= ch.pipeline();
  12. pipeline.addLast("framer",newDelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  13. pipeline.addLast("decoder",newStringDecoder());
  14. pipeline.addLast("encoder",newStringEncoder());
  15. // 客户端的逻辑
  16. pipeline.addLast("handler",newHelloClientHandler());
  17. }
  18. }

通道的业务处理程序

客户端的连接通道的业务处理程序与服务器类似,就不再过多累述。

  1. import io.netty.channel.ChannelHandlerContext;
  2. import io.netty.channel.SimpleChannelInboundHandler;
  3. public classHelloClientHandler extends SimpleChannelInboundHandler<String> {
  4. @Override
  5. protected voidchannelRead0(ChannelHandlerContext ctx, String msg)throwsException {
  6. System.out.println("Server say : "+ msg);
  7. }
  8. @Override
  9. public voidchannelActive(ChannelHandlerContext ctx) throwsException {
  10. System.out.println("Client active ");
  11. super.channelActive(ctx);
  12. }
  13. @Override
  14. public voidchannelInactive(ChannelHandlerContext ctx) throwsException {
  15. System.out.println("Client close ");
  16. super.channelInactive(ctx);
  17. }
  18. }

运行结果

客户端

Center

服务端

Center 1

发表评论

表情:
评论列表 (有 0 条评论,459人围观)

还没有评论,来说两句吧...

相关阅读