MyCat源码解析(1)


客户端输入mysql -h 127.0.0.1 -uroot -proot -DDTEST发生了什么:

1、首先mycat在启动的时候
使用一下代码启动一个服务线程
NIOAcceptor server = new NIOAcceptor(BufferPool.LOCAL_BUF_THREAD_PREX+ NAME + "Server", system.getBindIp(), system.getServerPort(),frontFactory, reactorPool);
server.start();
2、在NIOAcceptor的构造器中进行了NIO服务端的创建过程
    具体如下:
    1、打开ServerSocketChannel、用于监听客户端的连接、他是所有客户端连接的父通道
    this.serverChannel = ServerSocketChannel.open();
    2、绑定监听端口、设置为非阻塞状态
    this.serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(bindIp, port), 100);
3、创建多路复用器
this.selector = Selector.open();
4、将ServerSocketChannel注册到多路复用器上、监听Accetp事件
this.serverChannel.register(selector, SelectionKey.OP_ACCEPT);
5、在多路复用器NIOAcceptor线程的run方法中不断的轮训准备就绪的key,代码如下
for (;;) {
++acceptCount;
try {
selector.select(1000L);
Set<SelectionKey> keys = selector.selectedKeys();
try {
for (SelectionKey key : keys) {
if (key.isValid() && key.isAcceptable()) {


accept();
} else {
key.cancel();
}
}
} finally {
keys.clear();
}
} catch (Throwable e) {
LOGGER.warn(getName(), e);
}
}
6、客户端在终端输入mysql -h127.0.0.1 -uroot -proot -P8066 -DDTEST的时候、可以使用WireShark等抓包工具、发现客户端首先向服务端发送一个
一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文
7、此时NIOAcceptor多路复用器发现新的连接请求、调用accept方法进行后续的处理、包括TCP的三次握手信息
SocketChannel channel = serverChannel.accept();
设置为非阻塞状态
channel.configureBlocking(false);
     
     8、此时利用客户端SocketChannel构造一个Connection对象(实现为MySQLConnection对象)此时Connection对象中保存了新连接的客户端SocketChannel对象
Connection c = factory.make(channel);
c.setDirection(Connection.Direction.in);
c.setId(ConnectIdGenerator.getINSTNCE().getId());
InetSocketAddress remoteAddr = (InetSocketAddress) channel.getRemoteAddress();
c.setHost(remoteAddr.getHostString());
c.setPort(remoteAddr.getPort());



9、将第八步生成的Connection对象传递到网络处理器NIOReactor中进行处理
//派发此连接到某个Reactor处理
NIOReactor reactor = reactorPool.getNextReactor();


10、Reactor为网络反应器、具体创建过程在MyCatServer中、
在Reactor中有一个内部类RW为一个Runnable任务、
在RW 中保存着一个线程安全的链表队列、用于保存步骤8生成的Connection对象、放在队列中、基于消费者生产者的模式去处理链接Connection请求
11、在MyCat启动的时候、创建了自定义的几个网络反应器线程、线程的执行方法体被NIOReactor封装在一个RW任务当中、
具体代码在MyCatServer当中
//网络事件反应
NIOReactorPool reactorPool = new NIOReactorPool(BufferPool.LOCAL_BUF_THREAD_PREX + "NIOREACTOR", processorCount);


12、在RW的run方法中发现Connection队列中不为空、说明已经有了新的连接任务了、则使用第8步骤构造的Connection注册客户端连接通道Channel


processKey = channel.register(selector, SelectionKey.OP_READ, this);
this.handler.onConnected(this);


13、使用Connection当中NIOHandler对象来处理此次连接请求具体友MYSQLFrontConnectionHandler来处理
发送TCP三次认证数据
byte[] rand1 = RandomUtil.randomBytes(8);
byte[] rand2 = RandomUtil.randomBytes(12);


// 保存认证数据
byte[] seed = new byte[rand1.length + rand2.length];
System.arraycopy(rand1, 0, seed, 0, rand1.length);
System.arraycopy(rand2, 0, seed, rand1.length, rand2.length);
this.seed = seed;


// 发送握手包信息
HandshakePacket hs = new HandshakePacket();
hs.packetId = 0;
hs.protocolVersion = Versions.PROTOCOL_VERSION;
hs.serverVersion = Versions.SERVER_VERSION;
hs.threadId = id;
hs.seed = rand1;
hs.serverCapabilities = getServerCapabilities();
hs.serverCharsetIndex = (byte) (charsetIndex & 0xff);
hs.serverStatus = 2;
hs.restOfScrambleBuff = rand2;
hs.write(this);


14、随后客户端服务端完成TCP三次握手信息、处理流程和以上相同
当处理完成之后、服务器才接受到客户端你发送过来的链接语句
mysql -h127.0.0.1 -uroot -proot -P8066 -DDTEST
完成认证具体请求

猜你喜欢

转载自blog.csdn.net/chengzheng_IT/article/details/51274404
今日推荐