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中数据传输细节。
后续会逐步涉及到这个开源项目。
本文介绍了使用Netty实现简单的服务器和客户端的过程,包括配置、监听和服务交互等关键步骤,有助于理解Pinpoint的数据传输机制。
2011

被折叠的 条评论
为什么被折叠?



