Netty4服务端和客户端实现

女爷i 2022-11-01 13:43 410阅读 0赞

目录

目标

代码UML类图

服务端

客户端

Netty4实现服务端

Netty4实现客户端

测试

小结


目标

用netty4实现一个服务端和客户端,两者之间可以进行测试通信

代码UML类图

服务端

server.png

客户端

singleClient.png

Netty4实现服务端

服务类

  1. package com.mym.netty.server;
  2. import io.netty.bootstrap.ServerBootstrap;
  3. import io.netty.channel.*;
  4. import io.netty.channel.nio.NioEventLoopGroup;
  5. import io.netty.channel.socket.nio.NioServerSocketChannel;
  6. import io.netty.handler.codec.string.StringDecoder;
  7. import io.netty.handler.codec.string.StringEncoder;
  8. /**
  9. * netty服务端
  10. */
  11. public class NettyServer {
  12. public static void main(String[] args) {
  13. startServer();
  14. }
  15. public static void startServer(){
  16. //1.定义server启动类
  17. ServerBootstrap serverBootstrap = new ServerBootstrap();
  18. //2.定义工作组:boss分发请求给各个worker:boss负责监听端口请求,worker负责处理请求(读写)
  19. EventLoopGroup boss = new NioEventLoopGroup();
  20. EventLoopGroup worker = new NioEventLoopGroup();
  21. //3.定义工作组
  22. serverBootstrap.group(boss,worker);
  23. //4.设置通道channel
  24. serverBootstrap.channel(NioServerSocketChannel.class);//A
  25. //serverBootstrap.channelFactory(new ReflectiveChannelFactory(NioServerSocketChannel.class));//旧版本的写法,但是此过程在A中有同样过程
  26. //5.添加handler,管道中的处理器,通过ChannelInitializer来构造
  27. serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
  28. @Override
  29. protected void initChannel(Channel channel) throws Exception {
  30. //此方法每次客户端连接都会调用,是为通道初始化的方法
  31. //获得通道channel中的管道链(执行链、handler链)
  32. ChannelPipeline pipeline = channel.pipeline();
  33. pipeline.addLast(new StringDecoder());
  34. pipeline.addLast("serverHandler1",new ServerHandler());
  35. pipeline.addLast("serverHandler2",new ServerHandler2());
  36. pipeline.addLast(new StringEncoder());
  37. System.out.println("success to initHandler!");
  38. }
  39. });
  40. //6.设置参数
  41. //设置参数,TCP参数
  42. serverBootstrap.option(ChannelOption.SO_BACKLOG, 2048); //连接缓冲池的大小
  43. serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//维持链接的活跃,清除死链接
  44. serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);//关闭延迟发送
  45. //7.绑定ip和port
  46. try {
  47. ChannelFuture channelFuture = serverBootstrap.bind("0.0.0.0", 9099).sync();//Future模式的channel对象
  48. //7.5.监听关闭
  49. channelFuture.channel().closeFuture().sync(); //等待服务关闭,关闭后应该释放资源
  50. } catch (InterruptedException e) {
  51. System.out.println("server start got exception!");
  52. e.printStackTrace();
  53. }finally {
  54. //8.优雅的关闭资源
  55. boss.shutdownGracefully();
  56. worker.shutdownGracefully();
  57. }
  58. }
  59. }

Handler1

  1. package com.mym.netty.server;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.ChannelInboundHandlerAdapter;
  4. public class ServerHandler extends ChannelInboundHandlerAdapter {
  5. /*
  6. * ChannelInboundHandlerAdapter:ChannelInboundHandlerAdapter是ChannelInboundHandler的一个简单实现,默认情况下不会做任何处理,
  7. * 只是简单的将操作通过fire*方法传递到ChannelPipeline中的下一个ChannelHandler中让链中的下一个ChannelHandler去处理。
  8. *
  9. * SimpleChannelInboundHandler:SimpleChannelInboundHandler支持泛型的消息处理,默认情况下消息处理完将会被自动释放,无法提供
  10. * fire*方法传递给ChannelPipeline中的下一个ChannelHandler,如果想要传递给下一个ChannelHandler需要调用ReferenceCountUtil#retain方法。
  11. * */
  12. @Override
  13. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  14. System.out.println("ServerHandler receive msg:"+msg.toString());
  15. //写消息:先得到channel,在写如通道然后flush刷新通道把消息发出去。
  16. ctx.channel().writeAndFlush("this is ServerHandler reply msg happend at !"+System.currentTimeMillis());
  17. //把消息往下一个Handler传
  18. ctx.fireChannelRead(msg);
  19. }
  20. }

Handler2

  1. package com.mym.netty.server;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.ChannelInboundHandlerAdapter;
  4. public class ServerHandler2 extends ChannelInboundHandlerAdapter {
  5. @Override
  6. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  7. System.out.println("ServerHandler2 receive msg:"+msg.toString());
  8. ctx.channel().writeAndFlush("this is ServerHandler2 reply msg happend at !"+System.currentTimeMillis());
  9. }
  10. }

Netty4实现客户端

客户端服务类

  1. package com.mym.netty.client;
  2. import io.netty.bootstrap.Bootstrap;
  3. import io.netty.channel.*;
  4. import io.netty.channel.nio.NioEventLoopGroup;
  5. import io.netty.channel.socket.nio.NioSocketChannel;
  6. import io.netty.handler.codec.string.StringDecoder;
  7. import io.netty.handler.codec.string.StringEncoder;
  8. import java.io.BufferedReader;
  9. import java.io.InputStreamReader;
  10. /**
  11. * netty客户端
  12. */
  13. public class NettySingleClient {
  14. public static void main(String[] args) {
  15. startClient();
  16. }
  17. public static void startClient(){
  18. //1.定义服务类
  19. Bootstrap clientBootstap = new Bootstrap();
  20. //2.定义执行线程组
  21. EventLoopGroup worker = new NioEventLoopGroup();
  22. //3.设置线程池
  23. clientBootstap.group(worker);
  24. //4.设置通道
  25. clientBootstap.channel(NioSocketChannel.class);
  26. //5.添加Handler
  27. clientBootstap.handler(new ChannelInitializer<Channel>() {
  28. @Override
  29. protected void initChannel(Channel channel) throws Exception {
  30. System.out.println("client channel init!");
  31. ChannelPipeline pipeline = channel.pipeline();
  32. pipeline.addLast("StringDecoder",new StringDecoder());
  33. pipeline.addLast("StringEncoder",new StringEncoder());
  34. pipeline.addLast("ClientHandler",new ClientHandler());
  35. }
  36. });
  37. //6.建立连接
  38. ChannelFuture channelFuture = clientBootstap.connect("0.0.0.0",9099);
  39. try {
  40. //7.测试输入
  41. BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
  42. while(true){
  43. System.out.println("请输入:");
  44. String msg = bufferedReader.readLine();
  45. channelFuture.channel().writeAndFlush(msg);
  46. }
  47. } catch (Exception e) {
  48. e.printStackTrace();
  49. }finally {
  50. //8.关闭连接
  51. worker.shutdownGracefully();
  52. }
  53. }
  54. }

客户端的handler

  1. package com.mym.netty.client;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.ChannelInboundHandlerAdapter;
  4. public class ClientHandler extends ChannelInboundHandlerAdapter {
  5. @Override
  6. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  7. System.out.println("client receive msg:"+msg.toString());
  8. }
  9. }

测试

启动服务端和客户端后,客户端发送nihao!服务端回应,然后客户端发送hello,服务端回应。
服务端输出

  1. success to initHandler!
  2. ServerHandler receive msg:nihao
  3. ServerHandler2 receive msg:nihao
  4. ServerHandler receive msg:hello
  5. ServerHandler2 receive msg:hello

客户端输出

  1. client channel init!
  2. 请输入:
  3. nihao
  4. 请输入:
  5. client receive msg:this is ServerHandler reply msg happend at !1531893027697this is ServerHandler2 reply msg happend at !1531893027698
  6. hello
  7. 请输入:
  8. client receive msg:this is ServerHandler reply msg happend at !1531893045446this is ServerHandler2 reply msg happend at !1531893045447

小结

需要注意的是,服务端和客户端除了启动类和socket channel不一样以外,其他几乎一致的操作。

发表评论

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

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

相关阅读

    相关 Netty实现客户服务通信

    实现一个客户端与服务端通信的程序,可以使用socket网络编程来实现,而Netty作为一个封装了JDK的NIO通讯的异步事件驱动的网络应用框架,也同样可以实现。 1.创建M