tomcat NIO处理报文 是否需要拆包 粘包
文章目录
看了很多文章,有的说用有的说不用,还是看一下tomcat是如何解决的把。
首先有一点 默认的NIO boolean keptAlive = false;
普通HTTP请求粘包绝无可能,都是短链接(不包括upgrade (websocket协议之类)),accept 只获取一个连接,断开就结束。
消息头长度
tomcat对HTTP header的长度是有限制的 protocol.getMaxHttpHeaderSize() == 8192
也就是8kb
方法是:org.apache.coyote.http11.Http11Processor.service
parseRequestLine(读取所有请求头)
类NioEndPoint
// 会调用`NioEndpoint:fillReadBuffer`方法,填满8k
// 一次报文全部读完,如果超出就会发生异常,是异常
private int fillReadBuffer(boolean block, ByteBuffer to) throws IOException {
int nRead;
NioChannel channel = getSocket();
if (block) { // 注意 这里是false
// 省略
} else {
nRead = channel.read(to); // 一次读完清清楚楚
if (nRead == -1) {
throw new EOFException();
}
}
return nRead;
}
对于HTTP 消息体
// 正如往常的解决方法一样,如果是
long contentLength = request.getContentLengthLong();
if (contentLength >= 0) {
if (contentDelimitation) { // 方法在preopareRequest的时候会被设置为false
// contentDelimitation being true at this point indicates that
// chunked encoding is being used but chunked encoding should
// not be used with a content length. RFC 2616, section 4.4,
// bullet 3 states Content-Length must be ignored in this case -
// so remove it.
headers.removeHeader("content-length");
request.setContentLength(-1);
} else {
inputBuffer.addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]);// 保证了httpservletRequerst能通过inpustream来获取请求体消息
contentDelimitation = true;
}
}
得到一般结论,普通的HTTP请求拆包的解决就是,对于头消息,读8K,然后获取content-length,对于chunk数据就使用分隔符
tomcat keep-alive的实现
else if (state == SocketState.OPEN) {
// In keep-alive but between requests. OK to recycle
// processor. Continue to poll for the next request.
connections.remove(socket);
release(processor);
wrapper.registerReadInterest(); // 重新注册读事件
}
keep-alive的实现就是再次注册读事件!