随笔记录。

//创建一个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. screen对象和history对象

    history对象保存着用户上网的历史记录,从窗口被打开的那一刻开始算起 使用go()方法可以在用户的历史记录中任意跳转 history.go(-1);//后退一页 history.go(1);//前 ...

  2. jquery扩展实现input框字符长度限制中文2个字符,英文1个字符

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  3. python在使用redis时zadd错误

    最近在看<redis实战>,在写zadd时报错 Traceback (most recent call last): File "<stdin>", lin ...

  4. Forward团队-爬虫豆瓣top250项目-成员简介与分工

    马壮:擅长html,css,分工:分析网站源码 邢云淇:掌握python,java 分工:爬虫部分代码编写 张良:熟练掌握数据库 分工:数据库部分代码编写 年光宇:掌握c#,python 分工:代码整 ...

  5. Qt_模块简介

    Qt4 和 Qt5最大的区别之一就是底层架构有了修改.Qt5引入了模块化的概念,讲众多功能细分到几个模块之中.需要达到,用什么模块知道到哪个模块去寻找. Qt5模块分为Essentials Modul ...

  6. 6609 - Minimal Subarray Length

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_probl ...

  7. UIKit-UIBezierPath

    UIBezierPath精讲 http://www.henishuo.com/uibezierpath-draw/ iOS UIBezierPath类 介绍 http://justsee.iteye. ...

  8. js五道经典练习题--第二道仿qq聊天框

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  9. whereis+whatis+man

    使用Linux过程中无论是使用shell命令.程序开发或者用户文档都需要使用到强大的男人man命令. 使用方法也十分简单,以查看ls命令的使用方法为例: man ls man的搜索路径通常包括以下两个 ...

  10. Python自动化开发 - 函数式编程

    本节内容 一.函数式编程 二.高阶函数 1.变量可以指向函数 2.函数名也是变量 3.传入函数 三.返回函数 1.函数作为返回值 2.闭包特性 一.函数式编程 函数是Python内建支持的一种封装,我 ...