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 ...
随机推荐
- BZOJ 1444 [Jsoi2009]有趣的游戏 (AC自动机 + 概率DP + Gauss)
1444: [Jsoi2009]有趣的游戏 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1382 Solved: 498[Submit][Statu ...
- php,判断ajax,get,post
PHP自定义函数判断是否为Get.Post及Ajax提交的方法 /** * 是否是AJAx提交的 * @return bool */ function isAjax(){ if(isset($_SER ...
- Chapter14 糖酵解 糖异生 戊糖途径
糖酵解 一. 1.总览 产生丙酮酸 产生两个ATP 产生两个NADH 丙酮酸的去路: 产生乙醇 产生乳酸 乙酰辅酶A 参与其他合成 2.氧化磷酸化和之后的底物水平磷酸化是一个藕联过程 3.能量存在丙酮 ...
- 最顶尖的12个IT技能
这差不多是十年前得了,看看今天这些东西哪些死掉了,哪些成长茁壮了,又能有哪些启示. KevinScott是谷歌公司的高级技术经理,也是美国计算机协会专业与教育委 员会的创始成员,他说:“我在硅谷看到的 ...
- 20145232 韩文浩 《Java程序设计》第8周学习总结
教材学习内容总结 14 NIO与NIO2 NIO使用频道(channel)来衔接数据节点,对数据区的标记提供了clear(),rewind(),flip(),compact()等高级操作. 想要取得c ...
- 移动端 - APP测试要点
功能测试 1.运行 1)App安装完成后的试运行,可正常打开软件. 2)App打开测试,是否有加载状态进度提示. 3)App页面间的切换是否流畅,逻辑是否正确. 2.注册 1)同表单编辑页面 2)用户 ...
- js-数组面试题
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> & ...
- 走上模拟道路 HDU4891
http://vjudge.net/contest/view.action?cid=51327#problem/D Description Yoda: May the Force be with yo ...
- Android-Kotlin-抽象类与多态的表现
选择包名,然后右键: 选择Class类型,会有class: 选择File类型,不会自动有class: 目录结构: 定义描述抽象类 Person人类: package cn.kotlin.kotlin ...
- spring默认为单例模式
这两天看到一个bug,记录下. 在获取任务的时候,本来任务不是由这个柜员领取的,但是最后跑到那个柜员下面去了. 查看日志,发现两个任务的领取操作很近,日志是穿插着打的. 后来经人指点,说spring初 ...