APM开源项目pinpoint学习-netty学习

本文介绍了使用Netty实现简单的服务器和客户端的过程,包括配置、监听和服务交互等关键步骤,有助于理解Pinpoint的数据传输机制。

1、说明

pinpoint是通过netty作为内置服务器和客户端,实现agent(探针)与collector(数据采集)之间的通讯的。序列化使用的thrift。本人未接触过netty,因此按照其中的3.10版本做了个例子学习下。因为只是熟悉netty是如何监听服务,发送请求的,因此代码比较简单。也不涉及过多的内容。
经过源码分析发现,pinpoint并不是使用的原生netty,是和jboss结合使用的。

2、服务端编写

这里讲服务端所有代码放在一起,来写。
首先创建一个maven项目,并在pom.xml文件中引入netty3.10(目前netty已经到了5.x版本),这里仅仅是为了学习pinpoint。

<dependencies>
        <!-- 引入nett服务器 -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty</artifactId>
            <version>3.10.6.Final</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.0.18.Final</version>
        </dependency>
    </dependencies>

其次,使用netty创建服务器,并监听8000端口。
代码如下:
···
static DefaultChannelGroup group = new DefaultChannelGroup();
public static void main (String[] args) {
//创建服务端
NioServerSocketChannelFactory factory = new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),//boss线程池
Executors.newCachedThreadPool(),//worker线程池
8
);
//创建服务
ServerBootstrap bootstrap = new ServerBootstrap(factory);
//设置处理器
bootstrap.setPipelineFactory(new MyPipeLineFactory());

    Channel channel = bootstrap.bind(new InetSocketAddress("127.0.0.1",8000));

    group.add(channel);
    System.out.println("started");
}

···
注意对MyPipeLineFactory理解,个人理解这时管道流工厂,里面可以在管道添加我们自己的处理器。我们这里添加了字符编译、反编译、以及自己的业务处理器。这种结构的学习,对于理解pinpoint中PinpointServerAcceptor很有帮助。
下面我们看下MyPipeLineFactory:

//流处理类
    static class MyPipeLineFactory implements ChannelPipelineFactory {

        public ChannelPipeline getPipeline() throws Exception {
            ChannelPipeline pipeline = Channels.pipeline();
            //添加处理器和字符集处理防止出现断词
            pipeline.addLast("1",new MyDecoder());
            pipeline.addLast("2",new MyEncoder());
            //业务处理器
            pipeline.addLast("4",new MyChannelHandler());
            return pipeline;
        }
    }

代码没什么好讲的,我们分别看看MyDecoder:

//字符处理
    static class MyDecoder extends StringDecoder {
        @Override
        protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
            System.out.println("startdecoder");
            ChannelBuffer buffer = (ChannelBuffer) msg;//数据是channelBuffer格式的。
            byte[] m = buffer.array();
            if (m[m.length - 1] ==46) {//46 == '.'
                return new String(m, "UTF-8");
            }
            return null;
        }
    }

MyEncoder:

 static class MyEncoder extends StringEncoder {
        @Override
        protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
            String m = (String) msg;
            ChannelBuffer channelBuffer = ChannelBuffers.copiedBuffer(m, CharsetUtil.UTF_8);
            return channelBuffer;
        }
    }

接下来看看自己的业务处理器MyChannelHandler

 //自己处理类
    static class MyChannelHandler extends SimpleChannelHandler {
        @Override
        public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
            System.out.println("建立连接");
            group.add(e.getChannel());
        }

        @Override
        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
           System.out.println("接收消息:" + e.getMessage());
           //获取连接。消息发送是异步的,方法返回不一定发送完成,所以注册监听关闭连接
            final Channel channel = e.getChannel();//消息本身的连接
            ChannelFuture cf = channel.write("收到消息!....");//该实例保存了IO连接信息
            channel.write("lalalal.....");
            cf.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                    channel.close();
                }
            });

        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
            e.getChannel().close();//关闭连接
        }
    }

至此简单服务器就做好了,当然大家忽略掉里面对于连接的处理,这里只做学习,不涉及细节。
客户端代码类似,不同的是客户端是通过ClientBootStrap来连接的。

 public static void main(String[] args) {
        NioClientSocketChannelFactory factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool(),8);
        //客户端
        ClientBootstrap clientBootstrap = new ClientBootstrap(factory);
        clientBootstrap.setOption("tcpNoDelay",true);
        clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                ChannelPipeline pipeline = Channels.pipeline(new NettyServer.MyDecoder(),new NettyServer.MyEncoder(),new MyClientHandler());
                return pipeline;
            }
        });
        ChannelFuture channelFuture = clientBootstrap.connect(new InetSocketAddress("127.0.0.1",8000));
        System.out.println(channelFuture.isSuccess());
    }

这里客户端使用的是,上面服务端的Encoder和Decoder。我们只需要看看客户端handler:

static class MyClientHandler extends SimpleChannelHandler {
        @Override
        public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
            System.out.println("连接服务器");
            e.getChannel().write("sending......");
            e.getChannel().write("hahahaah.....");
        }

        @Override
        public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception {
            System.out.println("发送完成");
        }

        @Override
        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
           String m = (String) e.getMessage();
           System.out.println("接收消息:" + m);
           ChannelFuture channelFuture = e.getChannel().close();
           channelFuture.addListener(ChannelFutureListener.CLOSE);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
            System.out.println("失败了");
            e.getChannel().close();
        }
    }

3、理解

个人觉得,关键是理解channel(连接),channelFuture概念,弄清楚netty为了解决消息异步发送后,如何处理连接(通过ChannelFuture)。
通过这些简单学习,我们就可以了解pinpoint中数据传输细节。
后续会逐步涉及到这个开源项目。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值