当前位置: 首页 > news >正文

netty 学习 (1)

摘要 本文是学习Netty的第一篇文章,主要对Netty的Server和Client间的通讯机制进行验证。

netty server client


Server与Client建立连接后,会执行以下的步骤: 
1、Client向Server发送消息:Are you ok? 
2、Server接收客户端发送的消息,并打印出来。 
3、Server端向客户端发送消息:I am ok! 
4、Client接收Server端发送的消息,并打印出来,通讯结束。 

涉及到的类有4个: 
1、HelloServer :server类,启动Netty server 
2、HelloServerInHandler:server的handler,接收客户端消息,并向客户端发送消息 
3、HelloClient:client类,建立于Netty server的连接 

4、HelloClientIntHandler:client的handler,接收server端的消息,并向服务端发送消息

一、先加入必要的类库:

二、HelloServer代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

packagecom.yao.netty;

importio.netty.bootstrap.ServerBootstrap;

importio.netty.channel.ChannelFuture;

importio.netty.channel.ChannelInitializer;

importio.netty.channel.ChannelOption;

importio.netty.channel.EventLoopGroup;

importio.netty.channel.nio.NioEventLoopGroup;

importio.netty.channel.socket.SocketChannel;

importio.netty.channel.socket.nio.NioServerSocketChannel;

publicclass HelloServer {

    publicvoid start(intport) throwsException {

        EventLoopGroup bossGroup = newNioEventLoopGroup();

        EventLoopGroup workerGroup = newNioEventLoopGroup();

        try{

            ServerBootstrap b = newServerBootstrap();

            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)

                    .childHandler(newChannelInitializer<SocketChannel>() {

                        @Override

                        publicvoid initChannel(SocketChannel ch)

                                throwsException {

                            // 注册handler

                            ch.pipeline().addLast(newHelloServerInHandler());

                        }

                    }).option(ChannelOption.SO_BACKLOG,128)

                    .childOption(ChannelOption.SO_KEEPALIVE,true);

            ChannelFuture f = b.bind(port).sync();

            f.channel().closeFuture().sync();

        }finally{

            workerGroup.shutdownGracefully();

            bossGroup.shutdownGracefully();

        }

    }

    publicstatic void main(String[] args) throwsException {

        HelloServer server = newHelloServer();

        server.start(8000);

    }

}

三、 HelloServerInHandler代码如下: 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

packagecom.yao.netty;

importio.netty.buffer.ByteBuf;

importio.netty.channel.ChannelHandlerContext;

importio.netty.channel.ChannelInboundHandlerAdapter;

importorg.apache.commons.logging.Log;

importorg.apache.commons.logging.LogFactory;

// 该handler是InboundHandler类型

publicclass HelloServerInHandler extendsChannelInboundHandlerAdapter {

    privatestatic Log logger = LogFactory.getLog(HelloServerInHandler.class);

    @Override

    publicvoid channelRead(ChannelHandlerContext ctx, Object msg)

            throwsException {

        logger.info("HelloServerInHandler.channelRead");

        ByteBuf result = (ByteBuf) msg;

        byte[] result1 = newbyte[result.readableBytes()];

        // msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中

        result.readBytes(result1);

        String resultStr = newString(result1);

        // 接收并打印客户端的信息

        System.out.println("Client said:" + resultStr);

        // 释放资源,这行很关键

        result.release();

        // 向客户端发送消息

        String response = "I am ok!";

        // 在当前场景下,发送的数据必须转换成ByteBuf数组

        ByteBuf encoded = ctx.alloc().buffer(4* response.length());

        encoded.writeBytes(response.getBytes());

        ctx.write(encoded);

        ctx.flush();

    }

    @Override

    publicvoid channelReadComplete(ChannelHandlerContext ctx) throwsException {

        ctx.flush();

    }

}

四、HelloClient代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

packagecom.yao.netty;

importio.netty.bootstrap.Bootstrap;

importio.netty.channel.ChannelFuture;

importio.netty.channel.ChannelInitializer;

importio.netty.channel.ChannelOption;

importio.netty.channel.EventLoopGroup;

importio.netty.channel.nio.NioEventLoopGroup;

importio.netty.channel.socket.SocketChannel;

importio.netty.channel.socket.nio.NioSocketChannel;

publicclass HelloClient {

    publicvoid connect(String host, intport) throwsException {

        EventLoopGroup workerGroup = newNioEventLoopGroup();

        try{

            Bootstrap b = newBootstrap();

            b.group(workerGroup).channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE,true)

            .handler(newChannelInitializer<SocketChannel>() {

                @Override

                publicvoid initChannel(SocketChannel ch) throwsException {

                    ch.pipeline().addLast(newHelloClientIntHandler());

                }

            });

            // Start the client.

            ChannelFuture f = b.connect(host, port).sync();

            // Wait until the connection is closed.

            f.channel().closeFuture().sync();

        }finally{

            workerGroup.shutdownGracefully();

        }

    }

    publicstatic void main(String[] args) throwsException {

        HelloClient client = newHelloClient();

        client.connect("127.0.0.1",8000);

    }

}

五、 HelloClientIntHandler代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

packagecom.yao.netty;

importio.netty.buffer.ByteBuf;

importio.netty.channel.ChannelHandlerContext;

importio.netty.channel.ChannelInboundHandlerAdapter;

importorg.apache.commons.logging.Log;

importorg.apache.commons.logging.LogFactory;

publicclass HelloClientIntHandler extendsChannelInboundHandlerAdapter {

    privatestatic Log logger = LogFactory.getLog(HelloClientIntHandler.class);

    // 接收server端的消息,并打印出来

    @Override

    publicvoid channelRead(ChannelHandlerContext ctx, Object msg) throwsException {

        logger.info("HelloClientIntHandler.channelRead");

        ByteBuf result = (ByteBuf) msg;

        byte[] result1 = newbyte[result.readableBytes()];

        result.readBytes(result1);

        System.out.println("Server said:" + newString(result1));

        result.release();

    }

    // 连接成功后,向server发送消息

    @Override

    publicvoid channelActive(ChannelHandlerContext ctx) throwsException {

        logger.info("HelloClientIntHandler.channelActive");

        String msg = "Are you ok?";

        ByteBuf encoded = ctx.alloc().buffer(4* msg.length());

        encoded.writeBytes(msg.getBytes());

        ctx.write(encoded);

        ctx.flush();

    }

}

六、还有log4j.xml文件:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

<?xmlversion="1.0"?>

<!DOCTYPElog4j:configuration SYSTEM "log4j.dtd">

<log4j:configurationxmlns:log4j="http://jakarta.apache.org/log4j/">

    <appendername="CONSOLE"class="org.apache.log4j.ConsoleAppender">

        <layoutclass="org.apache.log4j.PatternLayout">

            <paramname="ConversionPattern"value="[%-5p] [%d] [%t] [%c] %m%n"/>

        </layout>

    </appender>

     

    <appendername="FILE"class="org.apache.log4j.DailyRollingFileAppender">

        <paramname="File"value="./log/netty.log"/>

        <layoutclass="org.apache.log4j.PatternLayout">

            <paramname="ConversionPattern"value="[%-5p] [%d] [%t] [%c] %m%n"/>

        </layout>

    </appender>

     

    <appendername="FILE_ERR"class="org.apache.log4j.DailyRollingFileAppender">

        <paramname="File"value="./log/netty_err.log"/>

        <paramname="Threshold"value="ERROR"/>

        <layoutclass="org.apache.log4j.PatternLayout">

            <paramname="ConversionPattern"value="[%-5p] [%d] [%t] [%c] %m%n"/>

        </layout>

    </appender>      

     

    <loggername="io.netty"additivity="false">

        <levelvalue="INFO,DEBUG"/>

        <appender-refref="FILE"/>

        <appender-refref="FILE_ERR"/>

        <appender-refref="CONSOLE"/>

    </logger>

    <loggername="com.yao"additivity="false">

        <levelvalue="INFO,DEBUG"/>

        <appender-refref="FILE"/>

        <appender-refref="FILE_ERR"/>

        <appender-refref="CONSOLE"/>

    </logger>

     

    <root>

         

      <levelvalue="debug"/>

        <appender-refref="FILE"/>

        <appender-refref="CONSOLE"/>

        <appender-refref="FILE_ERR"/>

    </root>

</log4j:configuration>

总结: 
通过上面简单的实例可以发现: 
1、在没有任何encoder、decoder的情况下,Netty发送接收数据都是按照ByteBuf的形式,其它形式都是不合法的。 
2、接收发送数据操作都是通过handler实现的,handler在netty中占据了非常重要的位置。 
3、netty的handler是基于事件触发的,例如当client连接server成功后,client中的HelloClientIntHandler的channelActive方法会自动调用。 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Java设计模式——工厂设计模式
  • Java开发中的23种设计模式详解(转)
  • CMMI学习
  • NetConf协议说明
  • HashMap 与 ConcurrentHashMap
  • java-策略模式
  • SNMP4J简介
  • SNMP 使用SNMP4J V2进行TRAP
  • JTable的清空小技巧以及JTable的详细介绍
  • JFrame简单的例子
  • org.apache.catalina.deploy.WebXml addFilter
  • Tomcat version 6.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 Web modules
  • myEclipse中的web项目直接引入到eclipse中运行
  • 常用的网络传输协议
  • extjs3.2中datefield和comboBox使用readOnly不正常显示
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • android 一些 utils
  • Bytom交易说明(账户管理模式)
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • express + mock 让前后台并行开发
  • HTML5新特性总结
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • js数组之filter
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • text-decoration与color属性
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 对超线程几个不同角度的解释
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 力扣(LeetCode)965
  • 新书推荐|Windows黑客编程技术详解
  • 译自由幺半群
  • ​​​​​​​开发面试“八股文”:助力还是阻力?
  • ######## golang各章节终篇索引 ########
  • (¥1011)-(一千零一拾一元整)输出
  • (1)bark-ml
  • (2024,Vision-LSTM,ViL,xLSTM,ViT,ViM,双向扫描)xLSTM 作为通用视觉骨干
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (二)Linux——Linux常用指令
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (函数)颠倒字符串顺序(C语言)
  • (蓝桥杯每日一题)love
  • (七)Java对象在Hibernate持久化层的状态
  • (转)winform之ListView
  • .bat文件调用java类的main方法
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .NET4.0并行计算技术基础(1)
  • .w文件怎么转成html文件,使用pandoc进行Word与Markdown文件转化
  • /etc/motd and /etc/issue
  • ??Nginx实现会话保持_Nginx会话保持与Redis的结合_Nginx实现四层负载均衡
  • @Autowired和@Resource的区别
  • @html.ActionLink的几种参数格式