最后:
总结来说,面试成功=基础知识+项目经验+表达技巧+运气。我们无法控制运气,但是我们可以在别的地方花更多时间,每个环节都提前做好准备。
面试一方面是为了找到工作,升职加薪,另一方面也是对于自我能力的考察。能够面试成功不仅仅是来自面试前的临时抱佛脚,更重要的是在平时学习和工作中不断积累和坚持,把每个知识点、每一次项目开发、每次遇到的难点知识,做好积累,实践和总结。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
/** 设置TCP属性 */
serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); //@1
serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 1024 * 16 * 2); //@2
// backlog=100
serverChannel.bind(new InetSocketAddress(bindIp, port), 100); //@3
this.serverChannel.register(selector, SelectionKey.OP_ACCEPT); //@4
this.factory = factory;
this.reactorPool = reactorPool;
}
重要属性一览:
-
port : 监听端口,例如默认mycat服务端口:8066,管理端口9066
-
selector : 选择器,主要关心OP_ACCEPT
-
factory : 前端连接工厂,用于将java.nio.SocketChannel包装成NioConnection。
-
reactorPool:从Reactor池。
代码@1,设置Socket选项,如果端口关闭,马上可再次使用。
代码@2,设置Socket的接收缓存区大小,32K。
代码@3,端口绑定。
代码@4,注册OP_ACCEPT事件。
1.2 run方法详解
public void run() {
final Selector tSelector = this.selector;
for (;😉 {
++acceptCount;
try {
tSelector.select(1000L);
Set keys = tSelector.selectedKeys();
try {
for (SelectionKey key : keys) {
if (key.isValid() && key.isAcceptable()) {
accept(); //@1
} else {
key.cancel();
}
}
} finally {
keys.clear();
}
} catch (Exception e) {
LOGGER.warn(getName(), e);
}
}
}
利用select()的多路复用技术,监听客户端的连接事件,并处理,重点关注代码@1,accept()方法的实现:
private void accept() {
SocketChannel channel = null;
try {
channel = serverChannel.accept();
channel.configureBlocking(false);
FrontendConnection c = factory.make(channel); //@1
c.setAccepted(true);
c.setId(ID_GENERATOR.getId());
NIOProcessor processor = (NIOProcessor) MycatServer.getInstance()
.nextProcessor();
c.setProcessor(processor); //@2
NIOReactor reactor = reactorPool.getNextReactor();
reactor.postRegister©; //@3
} catch (Exception e) {
LOGGER.warn(getName(), e);
closeChannel(channel);
}
}
代码@1,将客户端的Socket连接,包装成Mycat的业务对象,Connection,Connection工厂的作用主要是初始化Socket相关参数,以及为通道关联相关的业务处理器(Handler)。稍候重点浏览一下工厂相关的代码。
代码@2,每个通道从Mycat服务器的NioProcessor池中获取一个,在通道的整个生命周期中,只会与一个NioProcessor打交道。
代码@3,从从Reactor池中轮询获取一个Reacotr,注册该通道的读事件。
1.2.1 关于代码@1,Connection工厂代码如下
关于ServerConnectionFactory,这里有个非常重要的作用,就是设置相关Handler,比如ServerQueryHandler
,LoadDataInfileHandler,ServerPrepareHandler。从这里可以看出,Hander是线程通道安全的,线程安全的。
由代码@3处引出下一个主角,NioReactor,NioReactor将接管通道余下的所有关于读、写操作。
2、源码研读NIOReactor
================
在NIOAcceptor中,轮询获取一个NIOReactor,调用其postRegister()方法,将连接注册到事件分发器上(Selector),接下来从postRegister方法开始分析。
2.1 postRegister(AbstractConnection c)
final void postRegister(AbstractConnection c) {
reactorR.registerQueue.offer©;
reactorR.selector.wakeup();
}
mycat Reactor使用的是ConcurrentLikedQueue,无界队列,该方法将连接加入到任务队列尾部,然后唤醒selector.select()方法。
2.2 run 方法详解
@Override
public void run() {
final Selector selector = this.selector;
Set keys = null;
for (;😉 {
++reactCount;
try {
selector.select(500L);
register(selector); //@1
keys = selector.selectedKeys();
for (SelectionKey key : keys) {
AbstractConnection con = null;
try {
Object att = key.attachment();
if (att != null) {
con = (AbstractConnection) att;
if (key.isValid() && key.isReadable()) {
try {
con.asynRead(); // @2
} catch (IOException e) {
con.close(“program err:” + e.toString());
continue;
} catch (Exception e) {
LOGGER.warn(“caught err:”, e);
con.close(“program err:” + e.toString());
continue;
}
}
if (key.isValid() && key.isWritable()) {
con.doNextWriteCheck(); //@3
}
} else {
key.cancel(); //@4
}
} catch (CancelledKeyException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(con + " socket key canceled");
}
} catch (Exception e) {
LOGGER.warn(con + " " + e);
} catch (final Throwable e){
// Catch exceptions such as OOM and close connection if exists
//so that the reactor can keep running!
// @author Uncle-pan
// @since 2016-03-30
if(con != null){
con.close("Bad: "+e);
}
LOGGER.error("caught err: ", e);
continue;
}
}
} catch (Exception e) {
LOGGER.warn(name, e);
} catch (final Throwable e){
// Catch exceptions such as OOM so that the reactor can keep running!
// @author Uncle-pan
// @since 2016-03-30
LOGGER.error("caught err: ", e);
} finally {
if (keys != null) {
keys.clear();
}
}
}
}
NIOReactor是mycat线程模型的关键,而NioReactor的关键又是run方法,特别是对读写事件的处理。
代码@1,将主Reactor新接收的连接(SocketChannel)注册到从Reactor,用来监听读、写事件。
代码@2,读事件处理。
代码@3,写事件处理逻辑。
代码@4,如果键无效,则取消该键,该键关联的通道将会被关闭。
2.2.1 关于run()方法代码@1详解
private void register(Selector selector) {
AbstractConnection c = null;
if (registerQueue.isEmpty()) { //@1
return;
}
while ((c = registerQueue.poll()) != null) { //@2
try {
((NIOSocketWR) c.getSocketWR()).register(selector); //@3
c.register(); //@4
} catch (Exception e) {
c.close(“register err” + e.toString());
}
}
}
代码@1,如果没有新的连接,直接跳过注册这一步。
代码@2,将任务队列中的SocketChannel注册到该Selector上。
代码@3,NIOSocketWR,该类为通道的IO处理类,主要实现asynRead()、doNextWriteCheck()方法。直接调用通道的注册方法。
NIOSocketWR的register方法:
public void register(Selector selector) throws IOException {
try {
基础学习:
前端最基础的就是 HTML , CSS 和 JavaScript 。
网页设计:HTML和CSS基础知识的学习
HTML是网页内容的载体。内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字、图片、视频等。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
CSS样式是表现。就像网页的外衣。比如,标题字体、颜色变化,或为标题加入背景图片、边框等。所有这些用来改变内容外观的东西称之为表现。
动态交互:JavaScript基础的学习
JavaScript是用来实现网页上的特效效果。如:鼠标滑过弹出下拉菜单。或鼠标滑过表格的背景颜色改变。还有焦点新闻(新闻图片)的轮换。可以这么理解,有动画的,有交互的一般都是用JavaScript来实现的。
就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字、图片、视频等。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
[外链图片转存中…(img-tKp9286g-1715537469745)]
CSS样式是表现。就像网页的外衣。比如,标题字体、颜色变化,或为标题加入背景图片、边框等。所有这些用来改变内容外观的东西称之为表现。
[外链图片转存中…(img-z5Vp5wbi-1715537469746)]
动态交互:JavaScript基础的学习
JavaScript是用来实现网页上的特效效果。如:鼠标滑过弹出下拉菜单。或鼠标滑过表格的背景颜色改变。还有焦点新闻(新闻图片)的轮换。可以这么理解,有动画的,有交互的一般都是用JavaScript来实现的。
[外链图片转存中…(img-lrvIA0tB-1715537469747)]