随笔记录。

//创建一个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. Java EE JAR包的说明

    在java ee的开发中,jar文件是工程的基础,下面转载了网上兄弟一篇文章,简单介绍了一下,java ee中常用的jar文件的说明: activation.jar 与javaMail有关的jar包, ...

  2. Swift: 用UserDefaults保存复杂对象

    一直木有看过这个细节,用UserDefaults是能不能存复杂一点的对象.大家可能都看到过UserDefaults的一个方法setObject: forKey:,用这个方法存过NSDictionary ...

  3. java如何编写下载功能

    @RequestMapping("/downLoadFailRecord") public ModelAndView downLoadFailRecord( HttpServlet ...

  4. Establish a website in 5 minutes

    $sudo apt-get update                                    //update   $sudo apt-get install tasksel     ...

  5. security.php

    <?php /** * */ class Security { public function csrf_verify() { if(count($_POST) == 0) { return ' ...

  6. npm 及安装

    一.npm nodejs使开发者摆脱了浏览器的束缚,一系列基于nodejs的应用和工具不断出现,无论是在node应用的开发,还是使用中,包管理都扮演着一个很重要的作用.NPM(node package ...

  7. Delphi 与 Word_VBA

    '插入表格Sub setTable()  Set myRange = ActiveDocument.Range(Start:=2, End:=2)  ActiveDocument.Tables.Add ...

  8. js gettext

    test.php 1 <?php $locale='zh_CN'; if(isSet($_GET["locale"]))$locale = $_GET["local ...

  9. JS学习笔记5_DOM

    1.DOM节点的常用属性(所有节点都支持) nodeType:元素1,属性2,文本3 nodeName:元素标签名的大写形式 nodeValue:元素节点为null,文本节点为文本内容,属性节点为属性 ...

  10. 通过 NewLife.XCode 迁移任意现有数据库到任意数据库

    通过 NewLife.XCode 迁移任意现有数据库到任意数据库(附分表分库方法) 本文背景是将其他系统的数据库迁移到另一个数据库(仅需 20 行代码),也可以作为项目迁移用,生成自己系统的专属实体代 ...