请求信息包括以下三条
这里以请求行数据的解析为例,在 Http 协议中该行内容格式为:
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
Accepter
接收新的socket连接后,创建SocketProcessor
交给线程池运行。run
内调用AbstractProtocol.AbstractConnectionHandler.process
。AbstractHttp11Processor.process
,在此调用getInputBuffer().parseRequestLine(keptAlive)
、getInputBuffer().parseHeaders())
来解析请求行和请求头部。InternalInputBuffer.parseRequestLine
用fill
填充缓冲区,然后读取缓冲区来解析请求行。如果当前缓冲读完了,还不够解析,则继续调用fill
读取,如下: do { // 缓冲区读完了还不够这部分解析的,需要继续读取。 if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); // 没解析完读取流就见底了,报错 } ... chr = buf[pos++]; } while ((chr == Constants.CR) || (chr == Constants.LF));
Http11Processor
的构造函数中inputBuffer = new InternalInputBuffer(request, headerBufferSize);
,提供的headerBufferSize
就是最大长度。自行跟踪代码(全文搜索"ctrl+shift+f")可知道是8192)adapter.service(request, response);
,下篇文章讲解。BIO中,Accepter在接收新的socket连接后,创建新的线程,加入线程池来执行。每个连接(socket)对应一个线程,想必效率有限,也不适合高并发。
跟踪代码可知,AbstractEndpoint.createExecutor
中:
executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
其中getMaxThreads()
最终调用:
protected int getMaxThreadsExecutor(boolean useExecutor) {
if (useExecutor && executor != null) {
if (executor instanceof java.util.concurrent.ThreadPoolExecutor) {
return ((java.util.concurrent.ThreadPoolExecutor)executor).getMaximumPoolSize();
} else if (executor instanceof ResizableExecutor) {
return ((ResizableExecutor)executor).getMaxThreads();
} else {
return -1;
}
} else {
return maxThreads;
}
}
在executor没创建时,调用return maxThreads;
。其中maxThreads
在初始化时为200,因此线程池最大只能保持200个线程,支持的连接数应当也小于这个。在executor创建后,调用的是return ((java.util.concurrent.ThreadPoolExecutor)executor).getMaximumPoolSize();
,如果没变化(暂时没验证何时会使该值变化)则依旧是200。