随笔记录。

//创建一个ChannelFactory(客户端代码)

ChannelFactory factory = new NioClientSocketChannelFactory(

Executors.newCachedThreadPool(),

Executors.newCachedThreadPool());

// NioClientSocketChannelFactory构造方法

public NioClientSocketChannelFactory(

Executor bossExecutor, Executor workerExecutor,

int bossCount, int workerCount) {

...

// 线程池

this.bossExecutor = bossExecutor;

// 线程池

this.workerExecutor = workerExecutor;

// 构建ChannelSink,NioClientSocketPipelineSink实例

// bossCount默认1,workerCount默认Runtime.getRuntime().availableProcessors() * 2

sink = new NioClientSocketPipelineSink(

bossExecutor, workerExecutor, bossCount, workerCount);

}

// NioClientSocketPipelineSink构造方法

NioClientSocketPipelineSink(Executor bossExecutor, Executor workerExecutor,

int bossCount, int workerCount) {

this.bossExecutor = bossExecutor;

bosses = new Boss[bossCount];

for (int i = 0; i < bosses.length; i ++) {

bosses[i] = new Boss(i + 1);

}

workers = new NioWorker[workerCount];

for (int i = 0; i < workers.length; i ++) {

workers[i] = new NioWorker(id, i + 1, workerExecutor);

}

}

// 创建Bootstrap并设置factory(客户端代码)

ClientBootstrap bootstrap = new ClientBootstrap(factory);

// Bootstrap类set方法

public void setFactory(ChannelFactory factory) {

this.factory = factory;

}

// 设置ChannelPipelineFactory,实现getPipeline方法,返回一个ChannelPipeline实现类

// (客户端代码)

bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

public ChannelPipeline getPipeline() {

ChannelPipeline pipeline = Channels.pipeline();

pipeline.addLast("encode",new StringEncoder());

pipeline.addLast("decode",new StringDecoder());

pipeline.addLast("handler1",new TimeClientHandler());

return pipeline;

}

});

DefaultChannelPipeline类addLast方法

public synchronized void addLast(String name, ChannelHandler handler) {

if (name2ctx.isEmpty()) {

// 初始化name2ctx,head,tail

init(name, handler);

} else {

DefaultChannelHandlerContext oldTail = tail;

DefaultChannelHandlerContext    newTail =   new DefaultChannelHandlerContext(oldTail, null, name, handler);

// 最新的DefaultChannelHandlerContext放入tail以及更新到oldTail.next中

oldTail.next = newTail;

tail = newTail;

name2ctx.put(name, newTail);

}

}

// 客户端发起连接请求(客户端代码)

bootstrap.connect (new InetSocketAddress("127.0.0.1", 8080));

// connect源代码解读

ClientBootstrap类connect方法

public ChannelFuture connect(final SocketAddress remoteAddress,

final SocketAddress localAddress) {

ChannelPipeline pipeline;

try {

// 返回 DefaultChannelPipeline对象实例

pipeline = getPipelineFactory().getPipeline();

} catch (Exception e) {

throw new ChannelPipelineException("Failed to initialize a pipeline.", e);

}

// Set the options.

// 返回NioClientSocketChannelFactory实例,并创建NioClientSocketChannel实例

Channel ch = getFactory().newChannel(pipeline);

ch.getConfig().setOptions(getOptions());

// Bind.

if (localAddress != null) {

ch.bind(localAddress);

}

// Connect.

return ch.connect(remoteAddress);

}

NioClientSocketChannelFactory类newChannel方法

public SocketChannel newChannel(ChannelPipeline pipeline) {

//this为NioClientSocketChannelFactory实例

//pipeline为DefaultChannelPipeline实例

//sink为NioClientSocketPipelineSink实例

// sink.nextWorker返回一个NioWorker实例

return new NioClientSocketChannel(this, pipeline, sink, sink.nextWorker());

}

NioClientSocketChannel类构造方法

NioClientSocketChannel(

ChannelFactory factory, ChannelPipeline pipeline,

ChannelSink sink, NioWorker worker) {

//  新创建一个SocketChannel(newSocket() = > SocketChannel.open())

super(null, factory, pipeline, sink, newSocket(), worker);

fireChannelOpen(this);

}

继续看父类NioSocketChannel构造方法

public NioSocketChannel(

Channel parent, ChannelFactory factory,

ChannelPipeline pipeline, ChannelSink sink,

SocketChannel socket, NioWorker worker) {

super(parent, factory, pipeline, sink);

this.socket = socket;

this.worker = worker;

config = new DefaultNioSocketChannelConfig(socket.socket());

}

继续看父类AbstractChannel构造方法

protected AbstractChannel(

Channel parent, ChannelFactory factory,

ChannelPipeline pipeline, ChannelSink sink) {

// 传入了一个null值

this.parent = parent;

// NioClientSocketChannelFactory实例

this.factory = factory;

// DefaultChannelPipeline实例

this.pipeline = pipeline;

id = allocateId(this);

pipeline.attach(this, sink);

}

DefaultChannelPipeline类attach方法

public void attach(Channel channel, ChannelSink sink) {

// NioClientSocketChannel实例

this.channel = channel;

// NioClientSocketPipelineSink实例

this.sink = sink;

}

// ClientBootstrap类connect方法中ch.connect(remoteAddress)

//类AbstractChannel

public ChannelFuture connect(SocketAddress remoteAddress) {

return Channels.connect(this, remoteAddress);

}

//类Channels

public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) {

if (remoteAddress == null) {

throw new NullPointerException("remoteAddress");

}

ChannelFuture future = future(channel, true);

// DefaultChannelPipeline

// 新建一个ChannelState实例DownstreamChannelStateEvent

channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(

channel, future, ChannelState.CONNECTED, remoteAddress));

return future;

}

//类NioClientSocketPipelineSink

public void eventSunk(

ChannelPipeline pipeline, ChannelEvent e) throws Exception {

if (e instanceof ChannelStateEvent) {

ChannelStateEvent event = (ChannelStateEvent) e;

NioClientSocketChannel channel =

(NioClientSocketChannel) event.getChannel();

ChannelFuture future = event.getFuture();

ChannelState state = event.getState();

Object value = event.getValue();

switch (state) {

case OPEN:

if (Boolean.FALSE.equals(value)) {

channel.worker.close(channel, future);

}

break;

case BOUND:

if (value != null) {

bind(channel, future, (SocketAddress) value);

} else {

channel.worker.close(channel, future);

}

break;

case CONNECTED:

if (value != null) {

//第一次客户端发起连接

connect(channel, future, (SocketAddress) value);

} else {

channel.worker.close(channel, future);

}

break;

case INTEREST_OPS:

channel.worker.setInterestOps(channel, future, ((Integer) value).intValue());

break;

}

} else if (e instanceof MessageEvent) {

MessageEvent event = (MessageEvent) e;

NioSocketChannel channel = (NioSocketChannel) event.getChannel();

boolean offered = channel.writeBuffer.offer(event);

assert offered;

channel.worker.writeFromUserCode(channel);

}

}

private void connect(

final NioClientSocketChannel channel, final ChannelFuture cf,

SocketAddress remoteAddress) {

try {

// channel.socket在初始化NioClientSocketChannel时创建

//nio发起连接,因为设置了socket.configureBlocking(false)

//connect方法立即返回,返回值为false

//此时服务端已经收到了客户端发送的connect事件并进行处理

if (channel.socket.connect(remoteAddress)) {

channel.worker.register(channel, cf);

} else {

channel.getCloseFuture().addListener(new ChannelFutureListener() {

public void operationComplete(ChannelFuture f)

throws Exception {

if (!cf.isDone()) {

cf.setFailure(new ClosedChannelException());

}

}

});

cf.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);

channel.connectFuture = cf;

//注册事件,nextBoss()返回一个Runnable实例

nextBoss().register(channel);

}

} catch (Throwable t) {

cf.setFailure(t);

fireExceptionCaught(channel, t);

channel.worker.close(channel, succeededFuture(channel));

}

}

// Boss内部类 NioClientSocketPipelineSink

void register(NioClientSocketChannel channel) {

Runnable registerTask = new RegisterTask(this, channel);

Selector selector;

synchronized (startStopLock) {

if (!started) {

// Open a selector if this worker didn't start yet.

try {

// 打开一个选择器

this.selector = selector =  Selector.open();

} catch (Throwable t) {

throw new ChannelException(

"Failed to create a selector.", t);

}

// Start the worker thread with the new Selector.

boolean success = false;

try {

//启动线程,消费任务队列

//bossExecutor是客户端代码Executors.newCachedThreadPool()所创建

// nio的selector.select(500)操作

DeadLockProofWorker.start(

bossExecutor,

new ThreadRenamingRunnable(

this, "New I/O client boss #" + id + '-' + subId));

success = true;

} finally {

if (!success) {

// Release the Selector if the execution fails.

try {

selector.close();

} catch (Throwable t) {

logger.warn("Failed to close a selector.", t);

}

this.selector = selector = null;

// The method will return to the caller at this point.

}

}

} else {

// Use the existing selector if this worker has been started.

selector = this.selector;

}

assert selector != null && selector.isOpen();

started = true;

//写入队列一个注册任务

boolean offered = registerTaskQueue.offer(registerTask);

assert offered;

}

if (wakenUp.compareAndSet(false, true)) {

selector.wakeup();

}

}

//类DeadLockProofWorker

public static void start(final Executor parent, final Runnable runnable) {

//parent为bossExecutor,即一个线程池

......

//开启一个子线程

parent.execute(new Runnable() {

public void run() {

PARENT.set(parent);

try {

// ThreadRenamingRunnable实例

runnable.run();

} finally {

PARENT.remove();

}

}

});

}

//类ThreadRenamingRunnable

public void run() {

......

// Run the actual runnable and revert the name back when it ends.

try {

//runnable为Boss实例

runnable.run();

} finally {

if (renamed) {

// Revert the name back if the current thread was renamed.

// We do not check the exception here because we know it works.

currentThread.setName(oldThreadName);

}

}

}

// Boss内部类 NioClientSocketPipelineSink中

public void run() {

boolean shutdown = false;

Selector selector = this.selector;

long lastConnectTimeoutCheckTimeNanos = System.nanoTime();

for (;;) {

wakenUp.set(false);

try {

// 设置超时阻塞

int selectedKeyCount = selector.select(500);

if (wakenUp.get()) {

selector.wakeup();

}

// 消费队列中的事件

//nio中register操作

processRegisterTaskQueue();

if (selectedKeyCount > 0) {

//处理选择器获取到的事件

processSelectedKeys(selector.selectedKeys());

}

……

} catch (Throwable t) {

……

}

}

}

private void processRegisterTaskQueue() {

for (;;) {

//获取事件,task为registerTaskQueue.offer(registerTask);RegisterTask实例

final Runnable task = registerTaskQueue.poll();

if (task == null) {

break;

}

//执行NioClientSocketPipelineSink中的内部类RegisterTask的Run方法

task.run();

}

}

//内部类RegisterTask NioClientSocketPipelineSink中

public void run() {

try {

// nio socket注册,只有完成注册以后,才能和服务端进行通信

channel.socket.register(

boss.selector, SelectionKey.OP_CONNECT, channel);

} catch (ClosedChannelException e) {

channel.worker.close(channel, succeededFuture(channel));

}

……

}

private void processSelectedKeys(Set<SelectionKey> selectedKeys) {

for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {

SelectionKey k = i.next();

i.remove();

if (!k.isValid()) {

close(k);

continue;

}

if (k.isConnectable()) {

//完成客户端连接

connect(k);

}

}

}

private void connect(SelectionKey k) {

NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment();

try {

//nio完成客户端连接

if (ch.socket.finishConnect()) {

k.cancel();

//NioWorker类注册

ch.worker.register(ch, ch.connectFuture);

}

} catch (Throwable t) {

.......

}

}

类NioWorker负责读写事件注册处理

未完待续...

netty客户端源码的更多相关文章

  1. Netty 4源码解析:请求处理

    Netty 4源码解析:请求处理 通过之前<Netty 4源码解析:服务端启动>的分析,我们知道在最前端"扛压力"的是NioEventLoop.run()方法.我们指定 ...

  2. Netty5客户端源码解析

    Netty5客户端源码解析 今天来分析下netty5的客户端源码,示例代码如下: import io.netty.bootstrap.Bootstrap; import io.netty.channe ...

  3. Zookeeper 源码(三)Zookeeper 客户端源码

    Zookeeper 源码(三)Zookeeper 客户端源码 Zookeeper 客户端主要有以下几个重要的组件.客户端会话创建可以分为三个阶段:一是初始化阶段.二是会话创建阶段.三是响应处理阶段. ...

  4. swift实现饭否应用客户端源码

    swift 版 iOS 饭否客户端 源码下载:http://code.662p.com/view/13318.html 饭否是中国大陆地区第一家提供微博服务的网站,被称为中国版Twitter.用户可通 ...

  5. android版高仿淘宝客户端源码V2.3

    android版高仿淘宝客户端源码V2.3,这个版本我已经更新到2.3了,源码也上传到源码天堂那里了,大家可以看一下吧,该应用实现了我们常用的购物功能了,也就是在手机上进行网购的流程的,如查看产品(浏 ...

  6. C#中国象棋+游戏大厅 服务器 + 客户端源码

    来源:www.ajerp.com/bbs C#中国象棋+游戏大厅 服务器 + 客户端源码 源码开源 C#版中国象棋(附游戏大厅) 基于前人大虾的修改版 主要用委托实现 服务器支持在线人数,大厅桌数的设 ...

  7. FileZilla客户端源码解析

    FileZilla客户端源码解析 FTP是TCP/IP协议组的协议,有指令通路和数据通路两条通道.一般来说,FTP标准命令TCP端口号是21,Port方式数据传输端口是20. FileZilla作为p ...

  8. vs2008编译FileZilla客户端源码

    vs2008编译FileZilla客户端源码 下载FileZilla客户端源码,下载地址https://download.filezilla-project.org/. FileZilla客户端解决方 ...

  9. netty : NioEventLoopGroup 源码分析

    NioEventLoopGroup 源码分析 1. 在阅读源码时做了一定的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限.为了方便 IDE 查看.跟踪.调试 代码,所以在 github ...

随机推荐

  1. 线性回归,多项式回归(P2)

    回归问题 回归问题包含有线性回归和多项式回归 简单来说,线性回归就是用多元一次方程拟合数据,多项式回归是用多元多次来拟合方程 在几何意义上看,线性回归拟合出的是直线,平面.多项式拟合出来的是曲线,曲面 ...

  2. struts1(一)流程分析

  3. C#时间操作总结

    命名空间:System.Diagnostics Stopwatch 实例可以测量一个时间间隔的运行时间,也可以测量多个时间间隔的总运行时间.在典型的 Stopwatch 方案中,先调用 Start 方 ...

  4. mapnik渲染原理

    https://bbs.csdn.net/topics/390853826

  5. Eclipse添加servlet-api.jar库的引用

    右键Application-->Properties-->Java Build Path-->Libraries-->Add External JARs-->servle ...

  6. c简单的单向链表

    ps:list链表  node节点 在链表中节点就是一个个的结构体 堆空间由于在申请内存时,地址是随机的,所以要用链表的方式将其连接起来,但是链表头的地址要知道. 每个节点包含两个部分:数据区和地址区 ...

  7. java基础-day6

    第06天 java基础语法 今日内容介绍 u Eclipse断点调试 u 基础语法的练习 第1章   Eclipse断点调试 1.1      Eclipse断点调试概述 Eclipse的断点调试可以 ...

  8. SRM387 div1

    250pt: 题目:有一些盒子(不大于50个),每个盒子里有一些大理石(最多50种颜色),然后给定每个盒子里每种颜色大理石的个数(没有为0),求最少操作几步满足: 1:最多只能一个盒子里有多种颜色,叫 ...

  9. 数据统计--union all 执行多条sql

    需求--统计hive某张表type字段不同取值的数据量 我们已知某张表的type的取值是1,2,3,4,5,想要统计不同type的数据量,并清晰的展现出来.可以通过union all 的方式,sql如 ...

  10. uwsgi+nginx+django

    http://blog.csdn.net/c465869935/article/details/53242126 http://uwsgi-docs.readthedocs.io/en/latest/ ...