学习tomcat——如何建立连接,处理请求

NioEndpoint初始化之后,调用start()执行startInternal()

代码如下

// Create worker collection

if (getExecutor() == null) {

//创建线程池

createExecutor();

}

initializeConnectionLatch();

// Start poller thread

// 创建客户端队列(客户端过来的请求)

poller = new Poller();

Thread pollerThread = new Thread(poller, getName() + “-ClientPoller”);

pollerThread.setPriority(threadPriority);

pollerThread.setDaemon(true);

pollerThread.start();

//创建接收远程请求线程

startAcceptorThread();

初始化线程池配置

========================================================================

-> createExecutor() 用于处理用户请求

指定 备用线程,对大线程数,队列类型,超时时间,和线程工厂

public void createExecutor() {

internalExecutor = true;

TaskQueue taskqueue = new TaskQueue();

TaskThreadFactory tf = new TaskThreadFactory(getName() + “-exec-”, daemon, getThreadPriority());

executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);

taskqueue.setParent( (ThreadPoolExecutor) executor);

}

创建Poller线程

==========================================================================

poller = new Poller();

Thread pollerThread = new Thread(poller, getName() + “-ClientPoller”);

pollerThread.setPriority(threadPriority);

pollerThread.setDaemon(true);

pollerThread.start();

创建Acceptor线程

protected void startAcceptorThread() {

acceptor = new Acceptor<>(this);

String threadName = getName() + “-Acceptor”;

acceptor.setThreadName(threadName);

Thread t = new Thread(acceptor, threadName);

t.setPriority(getAcceptorThreadPriority());

t.setDaemon(getDaemon());

t.start();

}

处理请求的相关对象(线程)

=============================================================================

Acceptor类

=========================================================================

org.apache.tomcat.util.net.Acceptor

Acceptor 负责循环等待远程请求,将请求以socket形式携带信息,调用setSocketOptions()将socket包装配置为socketWrapper,

setSocketOptions: 对socket包装处理配置,使用poller对象注册到队列,让poller线程做后续的处理

Acceptor 类的run方法:

public void run() {

int errorDelay = 0;

//…以下省略部分代码

try {

// Loop until we receive a shutdown command

// 一直循环等待远程请求

while (!stopCalled) {

// Accept the next incoming connection from the server socket

// 1 接收请求

socket = endpoint.serverSocketAccept();

// setSocketOptions() will hand the socket off to

// 2 处理请求,setSocketOptions() 内部调用poller 将新请求任务放入队列

if (!endpoint.setSocketOptions(socket)) {

endpoint.closeSocket(socket);

}

}

} finally {

stopLatch.countDown();

}

state = AcceptorState.ENDED;

}

Poller类

=======================================================================

org.apache.tomcat.util.net.NioEndpoint.Poller

Poller负责接收包装后的socket请求,放入队列,

并在run方法中循环去poll()请求任务,将与流读写有关的组件IOChannel Selector socketWrapper 绑定关联

再通过selector获取selectionKeys

迭代循环获取对应的socket,提交任务(线程),线程读写处理socketWrapper等后续操作

public void run() {

// Loop until destroy() is called

while (true) {

// poller队列任务处理 将IOChannel Selector socketWrapper 关联

hasEvents = events();

//…省略

Iterator iterator =

keyCount > 0 ? selector.selectedKeys().iterator() : null;

// Walk through the collection of ready keys and dispatch

// 非阻塞io api 任务处理

while (iterator != null && iterator.hasNext()) {

SelectionKey sk = iterator.next();

iterator.remove();

NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();

// Attachment may be null if another thread has called

// cancelledKey()

if (socketWrapper != null) {

// 如果有等待处理的任务,则处理

processKey(sk, socketWrapper);

//processKey内部会调用processSocket方法,最终用线程池提交任务

}

}

// Process timeouts

timeout(keyCount,hasEvents);

}

getStopLatch().countDown();

}

其他

==================================================================

events队列

private final SynchronizedQueue events =

new SynchronizedQueue<>(); //事件队列(socket请求)

//注册请求到队列

public void rigister(final NioSocketWrapper socketWrapper)

{

event = new PollerEvent(socketWrapper, OP_REGISTER);

addEvent(event);

}

private void addEvent(PollerEvent event) {

events.offer(event);

if (wakeupCounter.incrementAndGet() == 0) {

selector.wakeup();

}

}

events()绑定及后面的 processSocket()最终提交实际处理任务到线程

/**

  • Processes events in the event queue of the Poller.

  • @return true if some events were processed,

  • false if queue was empty

*/

public boolean events() {

boolean result = false;

PollerEvent pe = null;

for (int i = 0, size = events.size(); i < size && (pe = events.poll()) != null; i++ ) {

result = true;

NioSocketWrapper socketWrapper = pe.getSocketWrapper();

SocketChannel sc = socketWrapper.getSocket().getIOChannel();

int interestOps = pe.getInterestOps();

if (sc == null) {

log.warn(sm.getString(“endpoint.nio.nullSocketChannel”));

socketWrapper.close();

} else if (interestOps == OP_REGISTER) {

try {

//注册绑定

sc.register(getSelector(), SelectionKey.OP_READ, socketWrapper);

} catch (Exception x) {

log.error(sm.getString(“endpoint.nio.registerFail”), x);

}

} else {

final SelectionKey key = sc.keyFor(getSelector());

if (key == null) {

// The key was cancelled (e.g. due to socket closure)

// and removed from the selector while it was being

// processed. Count down the connections at this point

// since it won’t have been counted down when the socket

// closed.

socketWrapper.close();

} else {

final NioSocketWrapper attachment = (NioSocketWrapper) key.attachment();

if (attachment != null) {

// We are registering the key to start with, reset the fairness counter.

try {

int ops = key.interestOps() | interestOps;

attachment.interestOps(ops);

key.interestOps(ops);

} catch (CancelledKeyException ckx) {

cancelledKey(key, socketWrapper);

}

} else {

cancelledKey(key, socketWrapper);

}

}

}

if (running && !paused && eventCache != null) {

pe.reset();//清空任务socketWrapper

eventCache.push(pe);

}

}

return result;

}

setSocketOptions 中的socket任务注册

protected boolean setSocketOptions(SocketChannel socket) {

NioSocketWrapper socketWrapper = null;

try {

// Allocate channel and wrapper

NioChannel channel = null;

if (nioChannels != null) {

channel = nioChannels.pop();

}

//… 部分省略

NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);

socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());

poller.register(socketWrapper);

return true;

} catch (Throwable t) {

最后

本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们

目录:

全靠这套面试题,才让我有惊无险美团二面拿offer  (面经解析)

Java面试核心知识点

一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!

全靠这套面试题,才让我有惊无险美团二面拿offer  (面经解析)

Java面试核心知识点

已经有读者朋友靠着这一份Java面试知识点指导拿到不错的offer了

全靠这套面试题,才让我有惊无险美团二面拿offer  (面经解析)

NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);

socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());

poller.register(socketWrapper);

return true;

} catch (Throwable t) {

最后

本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们

目录:

[外链图片转存中…(img-vs08BdFw-1718919914236)]

Java面试核心知识点

一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!

[外链图片转存中…(img-VMBlqBmk-1718919914236)]

Java面试核心知识点

已经有读者朋友靠着这一份Java面试知识点指导拿到不错的offer了

[外链图片转存中…(img-ywbUTI0y-1718919914237)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值