Netty服务端的业务流程分析
Netty的服务端怎么和java NIO联系起来的,一直很好奇这块内容,这里跟下代码,下篇文章看下Channel相关的知识。
finalChannelFuture initAndRegister(){
finalChannel channel = channelFactory().newChannel();//
try{
init(channel);
}catch(Throwable t){
channel.unsafe().closeForcibly();//立即关闭通道且不会触发事件
//因为这个通道还没有注册到EventLoop,所以我们需要强制GlobalEventExecutor的使用。
returnnewDefaultChannelPromise(channel,GlobalEventExecutor.INSTANCE).setFailure(t);
}
//注册一个EventLoop
ChannelFuture regFuture = group().register(channel);
//注册失败
if(regFuture.cause()!=null){
if(channel.isRegistered()){
channel.close();
}else{
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 程序运行到这里且promise没有失败,可能有如下几种情况
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
// 如果试图注册到一个EventLoop,该注册完成,
// i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
// added to the event loop's task queue for later execution.
// 如果试图注册到其他线程,该注册已经成功,但是没有完成,添加一个事件到任务队列中,等会执行
// i.e. It's safe to attempt bind() or connect() now:
// because bind() or connect() will be executed *after* the scheduled registration task is executed
// because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}
@Override
publicChannelFutureregister(Channel channel){
return next().register(channel);
}
@Override
publicChannelFutureregister(finalChannel channel,finalChannelPromise promise){
if(channel ==null){
thrownewNullPointerException("channel");
}
if(promise ==null){
thrownewNullPointerException("promise");
}
channel.unsafe().register(this, promise);
return promise;
}
@Override
publicfinalvoidregister(EventLoop eventLoop,finalChannelPromise promise){
if(eventLoop ==null){
thrownewNullPointerException("eventLoop");
}
if(isRegistered()){
promise.setFailure(newIllegalStateException("registered to an event loop already"));
return;
}
if(!isCompatible(eventLoop)){
promise.setFailure(
newIllegalStateException("incompatible event loop type: "+ eventLoop.getClass().getName()));
return;
}
AbstractChannel.this.eventLoop = eventLoop;
if(eventLoop.inEventLoop()){
register0(promise);
}else{
try{
eventLoop.execute(newOneTimeTask(){
@Override
publicvoid run(){
register0(promise);
}
});
}catch(Throwable t){
logger.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
@Override
protectedvoid doRegister()throwsException{
boolean selected =false;
for(;;){
try{
selectionKey = javaChannel().register(eventLoop().selector,0,this);
return;
}catch(CancelledKeyException e){
if(!selected){
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected =true;
}else{
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
wakeup
方法所得的结果privatestaticvoid doBind0(
finalChannelFuture regFuture,finalChannel channel,
finalSocketAddress localAddress,finalChannelPromise promise){
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(newRunnable(){
@Override
publicvoid run(){
if(regFuture.isSuccess()){
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}else{
promise.setFailure(regFuture.cause());
}
}
});
}
@Override
protectedvoid run(){
for(;;){
boolean oldWakenUp = wakenUp.getAndSet(false);
try{
if(hasTasks()){
selectNow();
}else{
select(oldWakenUp);
// 'wakenUp.compareAndSet(false, true)' is always evaluated
// before calling 'selector.wakeup()' to reduce the wake-up
// overhead. (Selector.wakeup() is an expensive operation.)
//
// However, there is a race condition in this approach.
// The race condition is triggered when 'wakenUp' is set to
// true too early.
//
// 'wakenUp' is set to true too early if:
// 1) Selector is waken up between 'wakenUp.set(false)' and
// 'selector.select(...)'. (BAD)
// 2) Selector is waken up between 'selector.select(...)' and
// 'if (wakenUp.get()) { ... }'. (OK)
//
// In the first case, 'wakenUp' is set to true and the
// following 'selector.select(...)' will wake up immediately.
// Until 'wakenUp' is set to false again in the next round,
// 'wakenUp.compareAndSet(false, true)' will fail, and therefore
// any attempt to wake up the Selector will fail, too, causing
// the following 'selector.select(...)' call to block
// unnecessarily.
//
// To fix this problem, we wake up the selector again if wakenUp
// is true immediately after selector.select(...).
// It is inefficient in that it wakes up the selector for both
// the first case (BAD - wake-up required) and the second case
// (OK - no wake-up required).
if(wakenUp.get()){
selector.wakeup();
}
}
cancelledKeys =0;
needsToSelectAgain =false;
finalint ioRatio =this.ioRatio;
if(ioRatio ==100){
processSelectedKeys();
runAllTasks();
}else{
finallong ioStartTime =System.nanoTime();
processSelectedKeys();
finallong ioTime =System.nanoTime()- ioStartTime;
runAllTasks(ioTime *(100- ioRatio)/ ioRatio);
}
if(isShuttingDown()){
closeAll();
if(confirmShutdown()){
break;
}
}
}catch(Throwable t){
logger.warn("Unexpected exception in the selector loop.", t);
// Prevent possible consecutive immediate failures that lead to
// excessive CPU consumption.
try{
Thread.sleep(1000);
}catch(InterruptedException e){
// Ignore.
}
}
}
}
Netty服务端的业务流程分析的更多相关文章
- Netty服务端的启动源码分析
ServerBootstrap的构造: public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, Serve ...
- Netty之旅三:Netty服务端启动源码分析,一梭子带走!
Netty服务端启动流程源码分析 前记 哈喽,自从上篇<Netty之旅二:口口相传的高性能Netty到底是什么?>后,迟迟两周才开启今天的Netty源码系列.源码分析的第一篇文章,下一篇我 ...
- 【Netty源码分析】Netty服务端bind端口过程
这一篇博客我们介绍一下Netty服务端绑定端口的过程,我们通过跟踪代码一直到NIO原生绑定端口的操作. 绑定端口操作 ChannelFuture future = serverBootstrap.bi ...
- Netty 服务端启动过程
在 Netty 中创建 1 个 NioServerSocketChannel 在指定的端口监听客户端连接,这个过程主要有以下 个步骤: 创建 NioServerSocketChannel 初始化并注 ...
- Netty 服务端创建
参考:http://blog.csdn.net/suifeng3051/article/details/28861883?utm_source=tuicool&utm_medium=refer ...
- netty服务端启动--ServerBootstrap源码解析
netty服务端启动--ServerBootstrap源码解析 前面的第一篇文章中,我以spark中的netty客户端的创建为切入点,分析了netty的客户端引导类Bootstrap的参数设置以及启动 ...
- Netty服务端NioEventLoop启动及新连接接入处理
一 Netty服务端NioEventLoop的启动 Netty服务端创建.初始化完成后,再向Selector上注册时,会将服务端Channel与NioEventLoop绑定,绑定之后,一方面会将服务端 ...
- Netty服务端Channel的创建与初始化
Netty创建服务端Channel时,从服务端 ServerBootstrap 类的 bind 方法进入,下图是创建服务端Channel的函数调用链.在后续代码中通过反射的方式创建服务端Channel ...
- netty服务端客户端启动流程分析
服务端启动流程 我们回顾前面讲解的netty启动流程,服务端这边有两个EventLoopGroup,一个专门用来处理连接,一个用来处理后续的io事件 服务端启动还是跟nio一样,绑定端口进行监听,我们 ...
随机推荐
- MongoDB shell基本操作
shell命令操作语法和JavaScript很类似,其实控制台底层的查询语句都是用JavaScript脚本完成操作的.使用shell 命令,需要启动mongo.exe.mongodb百科 常用shel ...
- BZOJ - 2142 礼物 (扩展Lucas定理)
扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...
- Tomcat 优化方案 和 配置详解
转载: http://blog.csdn.net/yi2672379417/article/details/51442229
- django的related_name
转:https://segmentfault.com/q/1010000003705677 就是一个反向关联的属性,比方说model里面定义两个class,一个是A,一个是B class A(Mode ...
- shell 去重
group=`cat config.properties | grep -v "^$" | grep -v "^# ...
- 基于Python语言使用RabbitMQ消息队列(一)
介绍 RabbitMQ 是一个消息中间人(broker): 它接收并且发送消息. 你可以把它想象成一个邮局: 当你把想要寄出的信放到邮筒里时, 你可以确定邮递员会把信件送到收信人那里. 在这个比喻中, ...
- win8.1系统相关
win8.1系统相关 信息时代,系统更新速度非常快,十一月初,同事在网上花5元买了一个win8.1系统激活码,之后两周,我电脑由于系统故障,准备重装系统,借助他的系统,但无法激活,借用他购买的账号也不 ...
- BZOJ2120:数颜色(分块版)
浅谈分块:https://www.cnblogs.com/AKMer/p/10369816.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?i ...
- 洛谷【P1714】切蛋糕
浅谈队列:https://www.cnblogs.com/AKMer/p/10314965.html 题目传送门:https://www.luogu.org/problemnew/show/P1714 ...
- Centos下安装禅道
1.下载禅道安装包:http://dl.cnezsoft.com/zentao/9.7/ZenTaoPMS.9.7.stable.zbox_64.tar.gz 2.将下载的压缩包解压到/opt目录下: ...