深入刨析tomcat 之---第3篇 HTTP/1.1 长连接的实现原理
writedby 张艳涛
长连接是HTTP/1.1的特征之一,1.1出现的原因是因为一个客户请求一个网页,这是一个http请求,这个网页中如果有图片,那么也会变为一个http请求,对于java客户端,一个http请求
是通过socket.getinputstream.cast(PrintWriter).println("http请求头"),如果俩个请求都通过一个socket来写数据,那么这个就是http长连接,如果你写一个简单http服务器,那你实现的就不是长连接,每次请求都把socket.close()了,
所以判断一个http请求时不是长连接就是判断socket.close有没有执行
那么我们来看tomcat是如何实现长连接了的,对应深入理解tomcat第4章
实现思路是,如果socket不断开的话,那么socket.getInputStream(),得到的in流 会调用in.read()方法,进行阻塞,如果来了数据,读取新进来的请求,如果满足http协议进行解析;
HttpProcessor类
public void run() { // Process requests until we receive a shutdown signal
while (!stopped) { // Wait for the next socket to be assigned
Socket socket = await();
if (socket == null)
continue; // Process the request from this socket
try {
process(socket);
} catch (Throwable t) {
log("process.invoke", t);
} // Finish up this request
connector.recycle(this); } // Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
threadSync.notifyAll();
} }
进入方法
private void process(Socket socket) {
boolean ok = true;
boolean finishResponse = true;
SocketInputStream input = null;
OutputStream output = null; // Construct and initialize the objects we will need
try {
input = new SocketInputStream(socket.getInputStream(),
connector.getBufferSize());
} catch (Exception e) {
log("process.create", e);
ok = false;
} keepAlive = true; while (!stopped && ok && keepAlive) { finishResponse = true; try {
request.setStream(input);
request.setResponse(response);
output = socket.getOutputStream();
response.setStream(output);
response.setRequest(request);
((HttpServletResponse) response.getResponse()).setHeader
("Server", SERVER_INFO);
} catch (Exception e) {
log("process.create", e);
ok = false;
} // Parse the incoming request
try {
if (ok) { parseConnection(socket);
parseRequest(input, output);
if (!request.getRequest().getProtocol()
.startsWith("HTTP/0"))
parseHeaders(input);
if (http11) {
// Sending a request acknowledge back to the client if
// requested.
ackRequest(output);
// If the protocol is HTTP/1.1, chunking is allowed.
if (connector.isChunkingAllowed())
response.setAllowChunking(true);
} }
异常...略
} // Finish up the handling of the request
if (finishResponse) {
try {
response.finishResponse();
} catch (IOException e) {
ok = false;
} catch (Throwable e) {
log("process.invoke", e);
ok = false;
}
try {
request.finishRequest();
} catch (IOException e) {
ok = false;
} catch (Throwable e) {
log("process.invoke", e);
ok = false;
}
try {
if (output != null)
output.flush();
} catch (IOException e) {
ok = false;
}
} // We have to check if the connection closure has been requested
// by the application or the response stream (in case of HTTP/1.0
// and keep-alive).
if ( "close".equals(response.getHeader("Connection")) ) {
keepAlive = false;
} // End of request processing
status = Constants.PROCESSOR_IDLE; // Recycling the request and the response objects
request.recycle();
response.recycle(); } try {
shutdownInput(input);
socket.close();
} catch (IOException e) {
;
} catch (Throwable e) {
log("process.invoke", e);
}
socket = null; }
进入方法
input.readRequestLine(requestLine);
接着进入
public void readRequestLine(HttpRequestLine requestLine)
throws IOException { // Recycling check
if (requestLine.methodEnd != 0)
requestLine.recycle(); // Checking for a blank line
int chr = 0;
do { // Skipping CR or LF
try {
chr = read();
} catch (IOException e) {
chr = -1;
}
} while ((chr == CR) || (chr == LF));
if (chr == -1)
throw new EOFException
(sm.getString("requestStream.readline.error"));
pos--; // Reading the method name
接着进入
public int read()
throws IOException {
if (pos >= count) {//读到了结尾
fill();
if (pos >= count)
return -1;
}
return buf[pos++] & 0xff;
}
接着
/**
* Fill the internal buffer using data from the undelying input stream.
*/
protected void fill()
throws IOException {
pos = 0;
count = 0;
int nRead = is.read(buf, 0, buf.length);
if (nRead > 0) {
count = nRead;
}
}
parseRequest(input, output); //input的构造方法
input = new SocketInputStream(socket.getInputStream(),
connector.getBufferSize()); //
public SocketInputStream(InputStream is, int bufferSize) { this.is = is;
buf = new byte[bufferSize]; }
上述俩个方法中的fill() 的is.read() 底层就是socket.getInputStream进行读到缓冲区
这个方法是有阻塞的,那么就实现了处理完一个http请求,接着读取第二个请求
如果以上过程报错,跳出while循环
try {
shutdownInput(input);
socket.close();
} catch (IOException e) {
;
} catch (Throwable e) {
log("process.invoke", e);
}
socket = null;
关闭socket,那么就断开了socket长连接
此文结束
深入刨析tomcat 之---第3篇 HTTP/1.1 长连接的实现原理的更多相关文章
- 深入刨析tomcat 之---第8篇 how tomcat works 第11章 11.9应用程序,自定义Filter,及注册
writed by 张艳涛, 标签:全网独一份, 自定义一个Filter 起因:在学习深入刨析tomcat的学习中,第11章,说了调用过滤链的原理,但没有给出实例来,自己经过分析,给出来了一个Filt ...
- 深入刨析tomcat 之---第2篇,解决第3章bug 页面不显示内容http://localhost:8080/servlet/ModernServlet?userName=zhangyantao&password=1234
writedby 张艳涛7月2日, 在学习第4张的过程中,发现了前一篇文章写的是关于1,2张的bug不用设置response响应头,需要在servlet的service()方法里面写是错误想 serv ...
- 深入刨析tomcat 之---第12篇 how tomcat works( 第17章 ) 解析catalina.bat 梳理启动流程
我们如何启动tomcat呢? 答案是双击startup.bat文件,这个文件在bin目录下 @echo off 不显示批处理命令 rem Licensed to the Apache Softw ...
- 深入刨析tomcat 之---第23篇 聊一下web容器的filter配置和defaultservet
writedby 张艳涛,在一个webapp应用程序内如何配置filter? <?xml version="1.0" encoding="ISO-8859-1&qu ...
- 深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理
writedby 张艳涛 web技术,以前的动态网页技术多是jsp页面,比如点击一个菜单目录,直接访问了一个LRJSDetailInput.jsp页面,这个页面 有<html><bo ...
- 深入刨析tomcat 之---第15篇 对应20章, myAdmin案例代码
writedby 张艳涛 有没有和我一样做到第20章的?今天基本结束了本书的阅读.最后一个案例没有demo,那我写了一回,如果有需要的可以在本地试试 路径 D:\wksp_study\designbo ...
- 深入刨析tomcat 之---第14篇 对应19章,使用manager管理 web应用
writedby 张艳涛 第19章讲的是管理程序,当一个tomcat启动的时候,能通过远程浏览器能访问tomcat,启动web应用,关闭web应用,查看web应用 怎么实现的呢? 在webapp 文件 ...
- 深入刨析tomcat 之---第13篇 tomcat的三种部署方法
writedby 张艳涛 一般我们都知道将web 应用打成war包,放到tomcat的webapp目录下,就是部署了,这是部署方法1 第2种部署方法我们也知道,就是讲web应用的文件夹拷贝到webap ...
- 深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件
writedby 张艳涛 记得当年是学习jsp的时候,写过web.xml中的标签.在之后的springmvc中也是有关于配置mvc 过滤器 和dispatchServlet的标签,之前是看不懂呢!看到 ...
随机推荐
- vue keep-alive从列表页进入详情页,再返回列表页时,还是之前滚动的位置
//router.js { path: '/oppo-music', component: () => import('@/views/OppoMusic.vue'), meta: { titl ...
- LuatOS | 全新在线模拟器,随时随地发挥创意
LuatOS --运行在嵌入式硬件的实时操作系统,开启全新物联网生态. 聚焦嵌入式应用生态,内置功能可支持绝大多数物联网应用场景.深度整合Lua语言,只需少量内存和Flash空间就能运行.不局限于合宙 ...
- 「模拟8.18」字符串(卡特兰数)·乌鸦喝水(树状数组,二分)·所驼门王的宝藏(tarjan,拓扑)
最近好颓啊,所以啥都做不出来 简单说一下这次考试,分机房了,还分不同考卷,果然我还是留在二机房的蒟蒻, 大概也只有这样的简单题,才能勉强水个rank 3吧........ 其实不必管在哪个机房,努力便 ...
- Golang控制子gorutine退出,并阻塞等待所有子gorutine全部退出
Golang控制子gorutine退出,并阻塞等待所有子gorutine全部退出 需求 程序有时需要自动重启或者重新初始化一些功能,就需要退出之前的所有子gorutine,并且要等待所有子goruti ...
- 一篇文章快速搞懂 Apache SkyWalking 的 OAL
OAL简介 在流模式(Streaming mode)下,SkyWalking 提供了 观测分析语言(Observability Analysis Language,OAL) 来分析流入的数据. OAL ...
- kube-controller-manager源码分析-AD controller分析
kubernetes ceph-csi分析目录导航 概述 kube-controller-manager组件中,有两个controller与存储相关,分别是PV controller与AD contr ...
- 4、mysql登录密码修改和找回
操作适合5.1-5.5:当前的环境是5.5的环境: 4.1.mysql启动的原理: mysqld_safe -> my.cnf ->mysql.sock http://blog.51cto ...
- .NET Core授权失败如何自定义响应信息?
前言 在.NET 5之前,当授权失败即403时无法很友好的自定义错误信息,以致于比如利用Vue获取到的是空响应,不能很好的处理实际业务,同时涉及到权限粒度控制到控制器.Action,也不能很好的获取对 ...
- Docker:docker搭建redis6.0.8集群
下载redis镜像 #拉取镜像 docker pull redis:6.0.8 查看版本 #查看版本 docker inspect redis 生成redis.conf配置文件 #在 /home/re ...
- 所有的Java虚拟机必须实现在每个类或接口被Java程序 “ 首次主动使用 ” 时才初始化他们
原文:https://www.cnblogs.com/fanjie/p/6916784.html Java程序对类的使用方式可分为两种– 主动使用– 被动使用 被动使用以后再讲,这里说说什么是主动使用 ...