netty客户端源码
随笔记录。
//创建一个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客户端源码的更多相关文章
- Netty 4源码解析:请求处理
Netty 4源码解析:请求处理 通过之前<Netty 4源码解析:服务端启动>的分析,我们知道在最前端"扛压力"的是NioEventLoop.run()方法.我们指定 ...
- Netty5客户端源码解析
Netty5客户端源码解析 今天来分析下netty5的客户端源码,示例代码如下: import io.netty.bootstrap.Bootstrap; import io.netty.channe ...
- Zookeeper 源码(三)Zookeeper 客户端源码
Zookeeper 源码(三)Zookeeper 客户端源码 Zookeeper 客户端主要有以下几个重要的组件.客户端会话创建可以分为三个阶段:一是初始化阶段.二是会话创建阶段.三是响应处理阶段. ...
- swift实现饭否应用客户端源码
swift 版 iOS 饭否客户端 源码下载:http://code.662p.com/view/13318.html 饭否是中国大陆地区第一家提供微博服务的网站,被称为中国版Twitter.用户可通 ...
- android版高仿淘宝客户端源码V2.3
android版高仿淘宝客户端源码V2.3,这个版本我已经更新到2.3了,源码也上传到源码天堂那里了,大家可以看一下吧,该应用实现了我们常用的购物功能了,也就是在手机上进行网购的流程的,如查看产品(浏 ...
- C#中国象棋+游戏大厅 服务器 + 客户端源码
来源:www.ajerp.com/bbs C#中国象棋+游戏大厅 服务器 + 客户端源码 源码开源 C#版中国象棋(附游戏大厅) 基于前人大虾的修改版 主要用委托实现 服务器支持在线人数,大厅桌数的设 ...
- FileZilla客户端源码解析
FileZilla客户端源码解析 FTP是TCP/IP协议组的协议,有指令通路和数据通路两条通道.一般来说,FTP标准命令TCP端口号是21,Port方式数据传输端口是20. FileZilla作为p ...
- vs2008编译FileZilla客户端源码
vs2008编译FileZilla客户端源码 下载FileZilla客户端源码,下载地址https://download.filezilla-project.org/. FileZilla客户端解决方 ...
- netty : NioEventLoopGroup 源码分析
NioEventLoopGroup 源码分析 1. 在阅读源码时做了一定的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限.为了方便 IDE 查看.跟踪.调试 代码,所以在 github ...
随机推荐
- java 冒泡排序 二分查找 选择排序 插入排序
下面这个程序是先定义一个整型数组,然后将其中的元素反序赋值,再用冒泡排序进行排序以后用二分查找来查找其中是否有某个数,返回值为-1时表示这个数可能小于这个数组的最小值或大小这个数组的最大值,-2表示这 ...
- RAW转换成RGB
clc; clear; close all; [filename,pathname]=uigetfile({'*.*','All Files (*.*)'},'Pick a file'); file ...
- Codeforces Round#413 Div.2
A. Carrot Cakes 题面 In some game by Playrix it takes t minutes for an oven to bake k carrot cakes, al ...
- (转)MVC一个页面多个submit
转自:http://stackoverflow.com/questions/442704/how-do-you-handle-multiple-submit-buttons-in-asp-net-mv ...
- HTML5表单新属性
HTML5表单新属性 autofocus 自动聚焦 <input type="text" autofocus> placeholder占位文本 tel ...
- FatMouse's Speed (hdu 1160)
#include <iostream> #include <cstdio> #include <cstring> #include <algori ...
- (多重背包)hdu--2191--悼念512汶川大地震遇难同胞——珍惜现在,感恩生活
Problem Description 急!灾区的食物依然短缺!为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品, ...
- noip第19课作业
1. 谁考了第K名 在一次考试中,每个学生的成绩都不相同,现知道了每个学生的学号和成绩,求考第k名学生的学号和成绩. [输入格式] 第一行有两个整数,分别是学生的人数n(1<=n<=100 ...
- 最通熟易懂的Hadoop HDFS实践攻略
HDFS是用来解决什么问题?怎么解决的? 如何在命令行下操作HDFS? 如何使用Java API来操作HDFS? 在了解基本思路和操作方法后,进一步深究HDFS具体的读写数据流程 学习并实践本文教程后 ...
- 深入探讨 Java 类加载器(转)
原帖地址:https://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要 ...