第一个netty程序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第一个netty程序相关的知识,希望对你有一定的参考价值。

  这是我刚开始学习netty写的第一个demo,原准备照着《Netty权威指南》的入门demo敲一边,等到我去下载jar包搭建环境的时候才发现Netty竟然没有5.x版本,现在最高 4.1.9。一脸懵逼的我一搜才知道Netty从5.x退回到4.x,具体原因不清楚。4.x与5.x毕竟隔着一个大版本,中间各种异同不是我这种小白现在能搞懂的,还是照着官方的demo来吧。下面这个例子就是参照官网guide中的demo修改而成,大概的逻辑是client 向 server请求server时间并打印。

服务端代码:

 1 public class TimeServerHandler extends ChannelInboundHandlerAdapter{
 2     
 3     /**
 4      * 每个传入的消息都要调用
 5      * */
 6     @Override
 7     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
 8         ByteBuf buf = (ByteBuf)msg;
 9         try{
10             byte[] req = new byte[buf.readableBytes()];
11             buf.readBytes(req);
12             String body = new String(req, "UTF-8");
13             System.out.println("服务器收到的请求:" + body);
14             String time = "Query time ?".equals(body) ? new Date().toString() : "fail";
15             ByteBuf resp = Unpooled.copiedBuffer(time.getBytes());
16             ctx.write(resp);
17         }finally{
18             buf.release();
19         }
20     }
21     
22     //通知ChannelInboundHandlerAdapter 最后一次对channelRead()的调用是当前批量读取中的最后一条消息。
23     @Override
24     public void channelReadComplete(ChannelHandlerContext ctx) {
25         /**
26          * ctx.write(resp) 是将信息写到消息队列,而不是每次write就写入SocketChannel
27          * ctx.flush() 是将消息发送队列中的信息写到SocketChannel中发送给对方,
28          * ctx.writeAndFlush(resp) 直接写入SocketChannel
29          * */
30         ctx.flush();
31     }
32     
33     //处理过程中出现的异常
34     @Override
35     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
36         cause.printStackTrace();
37         ctx.close();
38     }
39     
40 }

 

 1 public class TimeServer {
 2     public void bind(int port) throws Exception{
 3         //NIO线程组,专门用于处理网络事件,本质是Reactor线程组。
 4         EventLoopGroup bosser = new NioEventLoopGroup();//用于服务端接受客户端的连接
 5         EventLoopGroup worker = new NioEventLoopGroup();//用于进行SocketChannel的网络读写
 6         
 7         try {
 8             ServerBootstrap boot = new ServerBootstrap();//启动NIO服务端的辅助启动类,降低开发复杂度。
 9             
10             boot.group(bosser, worker)
11             .channel(NioserverSocketChannel.class)
12             .option(ChannelOption.SO_BACKLOG, 1024)//配置TCP参数
13             .childHandler(new ChannelInitializer<SocketChannel>(){//用于处理网络IO事件(记录日志,对消息进行编解码)
14                 @Override
15                 protected void initChannel(SocketChannel ch) throws Exception {
16                     ch.pipeline().addLast(new TimeServerHandler());
17                 }
18             });
19             
20             ChannelFuture cf = boot.bind(port).sync();//异步地绑定服务器,调用sync()方法阻塞等待直到绑定完成。
21             cf.channel().closeFuture().sync();//获取ChannelFuture,并且阻塞当前线程直到它完成。
22         } finally{
23             bosser.shutdownGracefully();//释放所有资源
24             worker.shutdownGracefully();
25         }
26         
27     }
28     
29     
30     public static void main(String[] args) {
31         int port = 8080;
32         try {
33             new TimeServer().bind(port);
34         } catch (Exception e) {
35             e.printStackTrace();
36         }
37     }
38 }

 

客户端代码:

 1 public class TimeClientHandler extends ChannelInboundHandlerAdapter{
 2     
 3     //在到服务器的连接已经建立之后将被调用
 4     @Override
 5     public void channelActive(ChannelHandlerContext ctx){
 6         byte[] req = "Query time ?".getBytes();
 7         ByteBuf firstMessage = Unpooled.buffer(req.length);
 8         firstMessage.writeBytes(req);
 9         ctx.writeAndFlush(firstMessage);
10     }
11     
12     //当从服务器接受到一条消息时被调用
13     @Override
14     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
15         ByteBuf buf = (ByteBuf)msg;
16         byte[] resp = new byte[buf.readableBytes()];
17         buf.readBytes(resp);
18         String str = new String(resp, "UTF-8");
19         System.out.println("服务器时间 : "+ str);
20     }
21     
22     @Override
23     public void channelReadComplete(ChannelHandlerContext ctx) {
24         ctx.flush();
25     }
26  
27     //处理过程中出现的异常
28     @Override
29     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
30         cause.printStackTrace();
31         ctx.close();
32     }
33       
34 }

 

public class TimeClient {
    public void connect(String host, int port) throws Exception{
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            Bootstrap boot = new Bootstrap();
            boot.group(group).channel(NioSocketChannel.class)
            .option(ChannelOption.TCP_NODELAY, true)
            .handler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new TimeClientHandler());
                }
                
            });
            
            ChannelFuture cf = boot.connect(host, port).sync();
            cf.channel().closeFuture().sync();
        }finally{
            group.shutdownGracefully();
        }
    }
    
    public static void main(String[] args) {
        final String host = "127.0.0.1";
        final int port = 8080;
        try {
            new TimeClient().connect(host, port);
        } catch (Exception e) {
            System.out.println("客户端" + Thread.currentThread().getId() + " 请求出现异常");
        }
                
    }
}

 

运行代码:

技术分享

技术分享

入门demo完成了,接下来就是在这个demo的基础上修改,后面的代码我也会一一记录。

以上是关于第一个netty程序的主要内容,如果未能解决你的问题,请参考以下文章

Netty网络编程实战1,搭建第一个Netty服务器

第一个netty程序

第3期:Java NIO框架——Netty介绍

netty第一个例子

片段不起作用并且有错误

自动刷新android片段,直到满足条件