1.pushlet原理
2.四种方法实现http服务
3.Tomcat处理http请求之源码分析 | 京东云技术团队
pushlet原理
Pushlet的基本使用形式极为简单,通常在多媒体视频、通讯应用中,如QuickTime,实现这一功能。Pushlet基于HTTP流技术,cd源码输出与加载HTTP页面后立即关闭连接的做法不同,它采用HTTP流方式主动推送新变更的数据到客户端,且在此期间HTTP连接始终保持打开状态。实现这种Keep-alive长连接的具体技术细节,请参考Sun提供的《HTTP Persistent Connection》和W3C的《HTTP1.1规范》。下面将通过示例来说明如何使用Pushlet。
示例1:
我们可以通过开发一个JSP页面,利用HTTP流技术不断向客户端发送新的HTML内容。该页面在一个定时器循环中实现这一功能:
<%
int i = 1
try { while (true) { out.print(""+(i++)+"")
out.flush()
try { Thread.sleep()
} catch (InterruptedException e) { out.print(""+e+"")
} } } catch (Exception e) { out.print(""+e+"")
}%>
上述示例中,我们利用JSP页面不断向客户端推送内容,但这种做法并不实用,因为新内容被机械地、持续不断地添加到页面中,而不是手机编辑源码服务器端更新的内容。
示例2:
现在,让我们深入探讨Pushlet的工作原理。通过运行Pushlet的示例源代码(examples/basics/push-js-stream.html),我们可以看到一个每3秒刷新一次的页面。那么它是如何实现的呢?
此示例包含了三个文件:push-js-stream.html、push-js-stream-pusher.jsp、push-js-stream-display.html。其中,push-js-stream.html为主框架文件,它以HTML Frame形式包含其他两个页面。
push-js-stream-pusher.jsp是一个JSP,执行在服务器端,其内容如下:
<%
/** Start a line of JavaScript with a function call to parent frame. */
String jsFunPre = " ";
int i = 1;
try {
// Every three seconds a line of JavaScript is pushed to the client
while (true) {
// Push a line of JavaScript to the client
out.print(jsFunPre+"Page "+(i++)+jsFunPost);
out.flush();
// Sleep three secs
try {
Thread.sleep();
} catch (InterruptedException e) {
// Let client display exception
out.print(jsFunPre+"InterruptedException: "+e+jsFunPost);
}
}
} catch (Exception e) {
// Let client display exception
out.print(jsFunPre+"Exception: "+e+jsFunPost);
}
%>
在示例1和示例2中使用JSP时存在一个问题:一些Servlet引擎在某个客户端离开时会“吃掉”IOException,导致JSP页面永远不会抛出此异常。因此,Pushlet采用Servlet的原因之一是能够捕获到IOException。在示例代码的第行,可以看到在一个定时器循环(3秒/周期)中打印了一些HTML内容并输出到客户端浏览器。请注意,炫播 源码这里推送的并非HTML而是JavaScript!
下面是JavaScript代码示例:
push-js-stream.html中的push()函数被名为pushletFrame的JSP Frame调用,将传入的参数值写入到displayFrame(此Frame为push-js-stream-display.html)。这是动态HTML的一个小技巧:使用document对象的writeln方法刷新某个Frame或Window的内容。
displayFrame成为了用于显示内容的、真正的视图。displayFrame初始化为黑色背景并显示“wait…”直到来自服务器的内容被推送过来:
WAIT...
这就是Pushlet的基本做法:从Servlet(或示例中的JSP)将JavaScript代码作为HTTP流推送到浏览器。这些代码被浏览器的JavaScript引擎解释并完成一些有趣的工作。因此,实现了从服务器端的Java到浏览器中的JavaScript的回调。
上述示例展示了Pushlet原理,但存在一些等待解决的问题和需要增强的特性。因此,建立了一个小型的服务器端Pushlet框架,并添加了一些用于客户端的JavaScript库。由于客户端需要依赖更多的DHTML特性(例如Layers),我们首先简要复习一些DHTML知识。示例代码见examples/dhtml。
DHTML(动态HTML)提供了在浏览器中维护内容、资源论坛源码进行用户交互的扩展能力。就像Java开发者使用Servlet和JSP那样,DHTML也应该是你的工具箱中的一部分。
DHTML涉及到HTML、级联样式表(CSS)、JavaScript和DOM。传统的页面只能通过重新加载来自服务器的新页面进行更新。DHTML提供了在页面被加载完毕后对浏览器内的HTML文档的完全控制。你应该见过一些带有“图像翻滚”、弹出内容、可收缩菜单功能的网页,它们便是使用DHTML技术实现的。尽管存在一些标准差异(见下面的“跨浏览器DHTML”),大多数兼容JavaScript1.4版本的浏览器(后面将简称为“版本4的浏览器”)都支持DHTML。
从开发者角度审视浏览器中的整个文档,如Frame、、表格等,它们都可以表示为具有层次的蜂蜜源码对象模式——DOM。通过使用JavaScript可以维护DOM成员,不仅可以改变文档的内容和外观,还可以捕捉例如鼠标移动、form提交这些用户事件,然后对DOM进行相应修改。例如,鼠标移动到上方可以产生“mouse-over”事件,这时通过显示高亮版本的或弹出解释性文字的方式修改页面外观。这听起来不错吧!我们现在就熟悉一下DHTML标准!但谁定义了DHTML标准?
这是DHTML初学者首先遇到的问题。首先,你需要一个版本4以上的浏览器。DHTML相关规范的官方标准出自World Wide Web Consortium (W3)。然而,微软和Netscape出品的版本4以上的浏览器都有一些私有的DHTML扩展,这是你必须注意的。
幸运的是,大多数用户都有版本4以上的浏览器,并且一些开发者(如Dannymen、Dan Steinman和Danny Goodman)建造了跨越浏览器的、可重用的DHTML库。
作为一名Java开发者,你应该适当地理解基于对象、甚至面向对象的JavaScript编程。在我的DHTML中你将找到一些示例,但了解更多的DHTML资源也是非常值得的。尤其在使用跨越浏览器的DHTML库对付那些顽固的浏览器问题时,一切都变得有趣、而不是枯燥。
就如Java获得在广阔的服务器端市场、DHTML在客户端领域具有许多强大特性那样,Pushlet以一种直接的方式将这两项伟大的技术捆绑在一起。接下来的章节将详细讨论Pushlet这个服务器端轻量级框架和客户端DHTML库。
四种方法实现http服务
当面临非Springboot项目中实现HTTP服务的需求时,有四种方法可供选择:基于Tomcat、Jetty、JdkHttp和Netty。这些内嵌web容器各有特色,适合不同的场景和性能需求。
Tomcat作为常见的选择,可通过添加Maven坐标并实现初始化代码来实现,如JdkSimpleDispatchServlet所示。它内置了Servlet支持,适用于基础需求。
Jetty与Tomcat类似,通过启动方法启动,其依赖相对简单。它的服务初始化代码简洁,对于Web支持同样较为全面。
Netty以其高性能脱颖而出,尤其适合高吞吐量应用。其pom依赖和启动方式都体现了其内置http编解码和协议支持的便利性。
最后,对于不依赖第三方的选项,JDK8内置的HttpServer提供了一种简单直接的方法。需下载rt包源码并在项目中配置,初始化服务的过程相对直接。
总的来说,选择哪种方法取决于具体项目的需求,如对Servlet规范的支持、性能要求以及对第三方依赖的考虑。每个选项都有其独特的优势,值得开发者根据实际情况灵活运用。
Tomcat处理http请求之源码分析 | 京东云技术团队
本文将从请求获取与包装处理、请求传递给 Container、Container 处理请求流程,这 3 部分来讲述一次 http 穿梭之旅。
在 tomcat 组件 Connector 启动时,会监听端口。以 JIoEndpoint 为例,在 Acceptor 类中,socket = serverSocketFactory.acceptSocket (serverSocket); 与客户端建立连接,将连接的 socket 交给 processSocket (socket) 来处理。在 processSocket 中,对 socket 进行包装,交给线程池处理。
线程池中的 SocketProcessor 任务,将 socket 交给 handler 处理,此 handler 为 HttpConnectionHandler 的实例。在 HttpConnectionHandler 的父类 process 方法中,根据请求的状态,创建 HttpProcessor 进行相应的处理,然后切到 HttpProcessor 的父类 AbstractHttpProccessor 中。
在 SocketProcessor 中,从 socket 获取请求数据,进行 keep-alive 处理,数据包装等操作,最终将处理后的请求信息交给了 CoyoteAdapter 的 service 方法。
CoyoteAdapter 的 service 方法中有两个主要任务:一是将 org.apache.coyote.Request 和 org.apache.coyote.Response 转换为继承自 HttpServletRequest 的 org.apache.catalina.connector.Request 和 org.apache.catalina.connector.Response,同时定位到 Context 和 Wrapper。二是将请求交给 StandardEngineValve 处理。
在 postParseRequest 方法中,request 通过 URI 的信息找到属于自己的 Context 和 Wrapper。Mapper 保存了所有的容器信息,初始化时将所有容器添加到了 mapper 中。容器信息的变化由 MapperListener 监听,一旦容器发生变化,MapperListener 将其作为监听者进行处理。
找到请求对应的 Context 和 Wrapper 后,CoyoteAdapter 将包装好的请求交给 Container 处理。从下面的代码片段,我们很容易追踪整个 Container 的调用链,形成时间线图。
最终,StandardWrapperValve 将请求交给 Servlet 处理完成,至此一次 http 请求处理完毕。
2024-12-27 14:32
2024-12-27 14:30
2024-12-27 13:55
2024-12-27 13:55
2024-12-27 13:46
2024-12-27 13:20
2024-12-27 13:16
2024-12-27 12:37