辅助链接

Dubbo系列之 (一)SPI扩展

Dubbo系列之 (二)Registry注册中心-注册(1)

Dubbo系列之 (三)Registry注册中心-注册(2)

Dubbo系列之 (四)服务订阅(1)

Dubbo系列之 (五)服务订阅(2)

Dubbo系列之 (六)服务订阅(3)

Dubbo系列之 (七)链路层那些事(1)

在讲解dubboTCP端的设计时,先了解下一些类的关系图。它们是如何组织在一起的,每个功能又是什么,接着在进一步深入了解其内涵。

类简介

1、Exchangers(交换器工具类) 用来创建TCP服务(bind)和建立客户端连接(connect)辅助类

2、Transporters(数据流传输工具类)用来创建TCP服务(bind)和建立客户端连接(connect)辅助类,Exchangers的底层内容依赖于Transporters,并且Transporters会根据SPI扩展,来适配合适的tcp通讯框架,比如netty,mina等。

3、Exchanger(交换器) 用来创建TCP链接,通过工具类Exchangers完成,该接口是一个SPI扩展,目前唯一仅有就是HeaderExchanger。从名字的含义可以得到,该协议是具有自定义协议头的交换器,所以取名HeaderExchanger。

4、Transporter(数据传输层) 用来创建TCP连接,通过工具类Transporters完成。它也是一个SPI扩展,比如NettyTransporter,MinaTransporter。

5、ExchangeClient (交换器客户端),Exchanger的connect()方法返回,即建立了TCP连接后,返回的客户端,接着就是通过该客户端与服务端通信,实例有HeaderExchangeClient、LazyConnectExchangeClient、ReferenceCountExchangeClient。之后分别讲解这3个,Exchangers工具类建立的连接客户端是HeaderExchangeClient。

6、ExchangeServer (交换器服务端端) Exchanger的bind()方法返回,即服务端监听的服务端实例,它监听这某个具体的tcp端口。默认实现是HeaderExchangeServer。

7、RemotingServer(远程的TCP服务端),ExchangeServer类也实现了该接口,代表其也是一个远程服务器,具体的实现有NettyServer,由Transporter的bind()方法返回,具体的Transporter返回相应的远程服务端。比如NettyTransporter#bind()返回NettyServer。

8、Client(TCP客户端),ExchangeClient类也实现了该接口,代表其也是一个TCP客户端,具体实现有NettyClient,由Transporter的connect()方法返回,具体的Transporter返回相应的TCP客户端。比如NettyTransporter#connect()返回NettyClient。

9、Channel (通信通道) ,每建立一个TCP链接就相应创建一个Channel。比如Netty建立连接后,就有一个Channel。这里的Channel指的是dubbo自己定义的一个channel。它与netty的channel建立关联,通过NettyChannel类,框架操作的是NettyChannel,而NettyChannel内部持有一个netty的channel对象。

10、HeaderExchangeChannel(交换器Channel,ExchangeChannel属于交换器Channel),它被HeaderExchangeClient客户端所持有,客户端就是通过HeaderExchangeChannel进行通信的,HeaderExchangeChannel内部持有一个具体的Channel。

11、ChannelHandler (通道处理器) 用来处理建立连接、发送请求、结束请求等操作的具体抽象。

12、ChannelHandlers(通道处理器工具类) 主要用来包裹封装具体的Channel,它的作用是通过消息类型,根据Dispatcher返回不同的

13、Dispatcher(消息派发器)

类型 Dispatcher Channelhandler 作用
All AllDispatcher AllChannelHandler 所有的消息类型全部通过业务线程池处理
Connection ConnectionOrderedDispatcher ConnectionOrderedChannelHandler 连接、断开消息单独通过一个线程池池来处理,其他的读写等消息通过业务线程池处理
Direct DirectDispatcher DirectChannelHandler 所有的消息都通过IO线程池处理,不放到业务线程池中
Execution ExecutionDispatcher ExecutionChannelHandler 请求消息在业务线程池处理,其他消息在IO线程池。
Message MessageOnlyDispatcher MessageOnlyChannelHandler 请求和响应消息在业务线程池处理,其他心跳,连接等消息在IO线程池处理

类关系图

试一把,Netty操作--客户端多线程,单链路(TCP)

1、定义传输消息

@Data
@ToString
public class SampleMessage { private String threadName; private String id; private String desc;
}

2、编写编码器

public class SampleEncoder extends MessageToByteEncoder<SampleMessage> {

    protected void encode(ChannelHandlerContext channelHandlerContext, SampleMessage sampleMessage, ByteBuf byteBuf) throws Exception {

        String threadName = sampleMessage.getThreadName();
String id = sampleMessage.getId();
String desc = sampleMessage.getDesc(); byteBuf.writeInt(threadName.getBytes().length);
byteBuf.writeBytes(threadName.getBytes()); byteBuf.writeInt(id.getBytes().length);
byteBuf.writeBytes(id.getBytes()); byteBuf.writeInt(desc.getBytes().length);
byteBuf.writeBytes(desc.getBytes());
String str = sampleMessage.getThreadName() + ":" + sampleMessage.getDesc() + ":" + sampleMessage.getId(); System.out.println(str);
}
}

3、编写解码器

public class SampleDecoder extends ByteToMessageDecoder {

    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {

        byteBuf.markReaderIndex();

        String threadName = read(byteBuf);
if (threadName == null) {
byteBuf.resetReaderIndex();
return;
} String id = read(byteBuf);
if (id == null) {
byteBuf.resetReaderIndex();
return;
} String desc = read(byteBuf);
if (desc == null) {
byteBuf.resetReaderIndex();
return;
} SampleMessage sampleMessage = new SampleMessage();
sampleMessage.setId(id);
sampleMessage.setThreadName(threadName);
sampleMessage.setDesc(desc);
list.add(sampleMessage);
} private String read(ByteBuf byteBuf) {
if (canReadInt(byteBuf)) {
int readInt = byteBuf.readInt();
if (canReadN(byteBuf, readInt)) {
byte[] bytes = new byte[readInt];
byteBuf.readBytes(bytes);
return new String(bytes);
}
}
return null;
} private boolean canReadInt(ByteBuf byteBuf) {
return canReadN(byteBuf, 4);
} private boolean canReadN(ByteBuf byteBuf, int n) {
if (!byteBuf.isReadable()) {
return false;
}
return byteBuf.readableBytes() >= n;
}
}

4、编写消息处理器

public class PrintChannelHandlers extends ChannelInboundHandlerAdapter {

    @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof SampleMessage) {
SampleMessage sampleMessage = (SampleMessage) msg;
System.out.println(sampleMessage.getThreadName() + ":" + sampleMessage.getId() + ":" + sampleMessage.getDesc());
}
} }

5、编写服务端

public class NettyServerMain {

    public static void main(String[] args) {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup(12))
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
// .addLast("log",new LoggingHandler(LogLevel.INFO))
.addLast("decoder", new SampleDecoder())
.addLast("encoder", new SampleEncoder())
.addLast("handler", new PrintChannelHandlers());
}
}); ChannelFuture channelFuture = serverBootstrap.bind(8888);
channelFuture.syncUninterruptibly();
System.out.println("链接前");
Channel channel = channelFuture.channel();
System.out.println("链接后");
}
}

6、编写客户端

public class NettyClientMain {
public static void main(String[] args) {
NettyClientMain nettyClientMain = new NettyClientMain();
nettyClientMain.open();
} public void open() {
Bootstrap bootstrap = new Bootstrap();
bootstrap = new Bootstrap();
bootstrap.group(new NioEventLoopGroup(10))
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.channel(NioSocketChannel.class); bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000);
bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
.addLast("decoder", new SampleDecoder())
.addLast("encoder", new SampleEncoder());
//.addLast("handler", new PrintChannelHandlers()); }
}); SocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8888); ChannelFuture future = bootstrap.connect(socketAddress);
boolean ret = future.awaitUninterruptibly(3000, MILLISECONDS); if (ret && future.isSuccess()) {
Channel newChannel = future.channel();
doProcess(newChannel);
}
} private void doProcess(Channel channel) { AtomicLong atomicLong = new AtomicLong();
for (int i = 0; i < 15; i++) {
final char ch = (char) (i + 65);
final String id = "id" + i;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
SampleMessage sampleMessage = new SampleMessage();
sampleMessage.setThreadName(Thread.currentThread().getName());
sampleMessage.setDesc(getdes(ch));
sampleMessage.setId("id" + sampleMessage.getDesc().length() + "-" + atomicLong.getAndIncrement());
channel.writeAndFlush(sampleMessage);
}
}
});
t.start();
}
} private String getdes(char a) {
Random random = new Random();
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < random.nextInt(500) + 1; i++) {
buffer.append(a);
}
return buffer.toString();
}
}

7、测试结果

结果符合预期,dubbo 也是通过服务底层公用一条TCP链接,多线程进行调用该链路channel。

Dubbo系列之 (七)链路层那些事(1)的更多相关文章

  1. Dubbo系列之 (七)网络层那些事(2)

    辅助链接 Dubbo系列之 (一)SPI扩展 Dubbo系列之 (二)Registry注册中心-注册(1) Dubbo系列之 (三)Registry注册中心-注册(2) Dubbo系列之 (四)服务订 ...

  2. dubbo系列十一、dubbo transport层记录

    前言 在dubbo接口方法重载且入参未显式指定序列化id导致ClassCastException分析时候用到了dubbo的通信层和编解码,dubbo有个transport层,默认使用netty4进行网 ...

  3. Android网络编程系列 一 TCP/IP协议族之链路层

    这篇借鉴的文章主要是用于后续文章知识点的扩散,在此特作备份和扩散学习交流. 数据链路层有三个目的: 为IP模块发送和 接收IP数据报. 为ARP模块发送ARP请求和接收ARP应答. 为RARP发送RA ...

  4. TCP/IP中最高大上的链路层简介(二)

    引言 对于程序猿来讲,似乎越接近底层,就越显得高大上.这也算是程序猿们的共同认知吧,虽然不是所有人.今天LZ就和各位一起探讨一下TCP/IP中最高大上的一层,也就是最底层的链路层. 这一层LZ了解的还 ...

  5. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  6. TCP/IP协议学习(六) 链路层详解

    学习知识很简单,但坚持不懈却又是如此的困难,即使一直对自己说"努力,不能停下"的我也慢慢懈怠了... 闲话不多说,本篇将讲述TCP/IP协议栈的链路层.在本系列第一篇我讲到,TCP ...

  7. Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7497260 更多请看专栏,地址 ...

  8. tcp/ip 卷一 读书笔记(2)物理层和链路层网络

    物理层和链路层网络 术语 链路 是一对相邻结点间的物理线路,中间没有任何其他的交换结点. 数据链路 除了物理线路外,还必须有通信协议来控制这些数据的传输. 帧 数据链路层的协议数据单元(PDU) 串行 ...

  9. [HTTP] tcp/ip详解 链路层 网络层 传输层 应用层

    1.可以把七层协议简化成四层协议链路层 网络层 传输层 应用层 2.通过路由器连接的两个网络网络层ip提供的是一个逐跳协议,提供了一种不可靠的服务,中间有可能会丢传输层tcp在ip的基础上提供了可靠的 ...

随机推荐

  1. 简谈DFS

    所谓DFS就是“不撞南墙不回头”的一种搜索.其时间复杂度为O(V+E). 能算出从起点到终点的全部路径,在算法执行的过程中需要一个visit[vi]数组来维护每个结点的访问情况,这样就能避免重复访问. ...

  2. 在.NET Core中使用MongoDB明细教程(1):驱动基础及文档插入

    MongoDB,被归类为NoSQL数据库,是一个以类JSON格式存储数据的面向文档的数据库系统.MongoDB在底层以名为bson的二进制编码格式表示JSON文档,MongoDB bson实现是轻量级 ...

  3. Typora markdown代码块显示序号

    打开偏好设置,找到代码块 打开显示行号 然后关闭Typora重新打开 此时代码块就有行号了

  4. 【AHOI 2015】 小岛 - 最短路

    描述 西伯利亚北部的寒地,坐落着由 N 个小岛组成的岛屿群,我们把这些小岛依次编号为 1 到 N . 起初,岛屿之间没有任何的航线.后来随着交通的发展,逐渐出现了一些连通两座小岛的航线.例如增加一条在 ...

  5. c/c++ 感悟 2008-10-03 02:08

    许久没有坐在电脑前写东西了.除了密密麻麻的英文小虫子,还是英文小虫子.今天不是解决bug,明天就是在创造bug,一句话不在bug中沉默就在bug中爆发.或许喜欢小宇宙爆发的样子吧,那样的感觉总是让人热 ...

  6. hive命令大全

    1.等值比较: =语法:A=B操作类型:所有基本类型描述: 如果表达式A与表达式B相等,则为TRUE:否则为FALSEhive> select 1 from iteblog where 1=1; ...

  7. 编译Uboot时出错:【已解决】 /bin/bash: arm-linux-gcc: command not found dirname: missing operand Try 'dirname --help' for more information.

    编译Uboot时出错: 错误信息如下: /bin/bash: arm-linux-gcc: command not found dirname: missing operand Try 'dirnam ...

  8. AS 新安装Android Studio运行项目前报错:Unable to access Android SDK add-on list

    新安装Android Studio运行项目前报错:Unable to access Android SDK add-on list AS启动后,会在默认路径下检测是否有Android SDK,如果没有 ...

  9. unity探索者之socket传输protobuf字节流(四)

    版权声明:本文为原创文章,转载请声明http://www.cnblogs.com/unityExplorer/p/7027659.html 上篇已经把socket的传输说的差不多了,这篇主要是说说断线 ...

  10. 浅析XML和JSON的区别

    前言 今天做接口对接时,发现对方竟然是通过XML进行数据传输,当时冒出的第一个想法就是:WTF,这都什么年代了,还在用XML,是来搞笑的吧,JSON它不香吗? 想法归想法,但对接还是要完成的是吧?然后 ...