(转)OpenFire源码学习之十二:HttpBind&Script Syntax
转:http://blog.csdn.net/huwenfeng_2011/article/details/43417343
HttpSessionManager
该类管理所有通过httpbing连接到openfire的议定。它是一个同步http的双向流
http://www.xmpp.org/extensions/xep-0124.html
构造方法:HttpSessionManager()
配置一个汇集执行者对异步路由传进来的数据的默认大小配置默认为60秒
注意:在默认情况下,服务支持最大254个客户端。这时候BOSH 承载着非常大的负荷,那么这就需要额外的分配一些线程池容量以供客户端及时入站点。
- public HttpSessionManager() {
- this.sessionManager = SessionManager.getInstance();
- int poolSize = JiveGlobals.getIntProperty("xmpp.httpbind.worker.threads",
- JiveGlobals.getIntProperty("xmpp.client.processing.threads", 16));
- int keepAlive = JiveGlobals.getIntProperty("xmpp.httpbind.worker.timeout", 60);
- sendPacketPool = new ThreadPoolExecutor(poolSize, poolSize, keepAlive, TimeUnit.SECONDS,
- new LinkedBlockingQueue<Runnable>(), // unbounded task queue
- new ThreadFactory() { // custom thread factory for BOSH workers
- final AtomicInteger counter = new AtomicInteger(1);
- public Thread newThread(Runnable runnable) {
- Thread thread = new Thread(Thread.currentThread().getThreadGroup(), runnable,
- "httpbind-worker-" + counter.getAndIncrement());
- thread.setDaemon(true);
- return thread;
- }
- });
- }
ThreadPoolExecutor该线程池配置了:池中所保持的线程数和最大线程数均为poolSize(16),
keepAlive多余空闲线程等待心任务的的最长时间。
TimeUnit.SECONDS:参数的时间单位
newLinkedBlockingQueue<Runnable>():执行前保持的队列,此队列仅保持由execute 方法提交的 Runnable 任务。
ThreadFactory:执行程序创建新线程时使用的工厂。
启动sessionManager
- public void start() {
- inactivityTask = new HttpSessionReaper();
- TaskEngine.getInstance().schedule(inactivityTask, 30 * JiveConstants.SECOND,
- 30 * JiveConstants.SECOND);
- sendPacketPool.prestartCoreThread();
- }
HttpSessionReaper该类是个记时任务类。覆盖了TimerTask中的run方法。我们先看看该方法的内容
- public void run() {
- long currentTime = System.currentTimeMillis();
- for (HttpSession session : sessionMap.values()) {
- long lastActive = currentTime - session.getLastActivity();
- if (Log.isDebugEnabled()) {
- Log.debug("Session was last active " + lastActive + " ms ago: " + session.getAddress());
- }
- if (lastActive > session.getInactivityTimeout() * JiveConstants.SECOND) {
- Log.info("Closing idle session: " + session.getAddress());
- session.close();
- }
- }
- }
session.getLastActivity():这个方法以毫秒为时间单位返回关闭http连接的时间。
getInactivityTimeout() 这个方法以秒为单位返回不活跃或被终止会话时间
这里用系统时间减去http关闭连接时间。也就是说在关闭连接的时间与系统当先的这段时间,该会话在服务端系统就是一个闲置的状态。下面的方法:
- if (lastActive > session.getInactivityTimeout() * JiveConstants.SECOND) {
- Log.info("Closing idle session: " + session.getAddress());
- session.close();
- }
当这个闲置时间大于这个不活跃或被关闭连接的时候,这里就执行session.close()方法来结束这个会话。
回过头来,再看start()方法。
- TaskEngine.getInstance().schedule(inactivityTask, 30 * JiveConstants.SECOND,30 * JiveConstants.SECOND);
TaskEngine该类使用工作线程来执行任务。它还可以安排任务执行的时间,该类模拟了ExecutorService和Timer。任何TimerTask,按预定计划运行在未来将会被自动运行使用线程执行器的线程池。这意味着标准的限制,TimerTasks并不适用快速运行。
Schedule()方法:
安排指定重复任务(固定的延迟执行)。Subsequent executions take place at approximatelyregular intervals separated by the specified period.
在固定延迟执行,每个执行计划相对于实际执行时间前执行。如果一个执行延迟由于任何原因(如垃圾回收或其他后台活动),后续执行也将推迟。从长远来看,执行的频率通常是略低于指定的周期的倒数(假设系统时钟底层对象等(长)是准确的)。
固定延迟执行适当的重复出现的活动,要求“smoothness“换句话说,它是适合他们的活动,更重要的是要保持频率准确在短期内比从长远来看。这包括大多数动画任务,如闪烁的光标定期。它还包括任务中执行常规的活动在回应人类输入,如自动重复字符只要一个关键是压低频率。
调用该方法的三个参数:
inactivityTask:需要调度的任务
30 * JiveConstants.SECOND:执行任务之前延迟的毫秒数
30 * JiveConstants.SECOND:连续执行任务的间隔毫秒
最后一步:
sendPacketPool.prestartCoreThread();
该方法启动核心线程,使其处于等待工作的空闲状态。仅当执行新任务时,此操作才重写默认的启动核心线程策略。
HttpBindServer
- public void setHttpBindPorts(int unsecurePort, int securePort) throws Exception {
- changeHttpBindPorts(unsecurePort, securePort);
- bindPort = unsecurePort;
- bindSecurePort = securePort;
- if (unsecurePort != HTTP_BIND_PORT_DEFAULT) {
- JiveGlobals.setProperty(HTTP_BIND_PORT, String.valueOf(unsecurePort));
- }
- else {
- JiveGlobals.deleteProperty(HTTP_BIND_PORT);
- }
- if (securePort != HTTP_BIND_SECURE_PORT_DEFAULT) {
- JiveGlobals.setProperty(HTTP_BIND_SECURE_PORT, String.valueOf(securePort));
- }
- else {
- JiveGlobals.deleteProperty(HTTP_BIND_SECURE_PORT);
- }
- }
首先看看changeHttpBindPorts(unsecurePort, securePort)方法:
- private synchronized void changeHttpBindPorts(int unsecurePort, int securePort)
- throws Exception {
- .......
- if (httpBindServer != null) {
- try {
- httpBindServer.stop();
- }
- catch (Exception e) {
- Log.error("Error stopping http bind server", e);
- }
- }
- configureHttpBindServer(unsecurePort, securePort);
- httpBindServer.start();
- }
在这段代码里面主要设计到的有两个方法
方法一:confingureHttpBindServer(unsecurePort,securePort)
该方法主要为一个httpbind指定两个端口:
一个是:正常httpbind服务端口,7070另一个为:TLS安全HTTP绑定端口。7443
该方法中用到了一个jetty类QueuedThreadPool。
解释下一个类。该类是jetty的一个线程池,它实现了org.eclipse.jetty.util.thread.ThreadPool接口,并继承org.eclipse.jetty.util.component.AbstractLifeCycle。
在里是为了给该线程池设置一线程名称。
然后创建连接,of与jetty中创建连接用到了SelectChannelConnector。它继承了
AbstractNIOConnector。它选择NIO连接器。这个连接器使用NIO缓冲器与非有效阻止线程模型。直接使用NIO缓冲区和线程只分配给连接请求。同步是用来模拟阻塞为servletAPI,和任何冲内容尽头的请求处理是异步写的。这个连接器是最好的用于当有许多空闲时间的连接。
使用延续,支持无线的等待。如果一个过滤器或servlet返回后调用Continuation.suspend()或者延续暂停期间抛出一个运行时异常时从一个调用Continuation.undispatch(),Jetty将不会发送响应给客户端。相反,线程被释放和延续是放置在定时器队列。如果连续超时过期,或它的恢复方法被调用,然后再次请求分配给一个线程和请求重试。这种方法的局限性是,请求内容不可用于重试请求,因此如果可能应该阅读后的延续或保存为请求属性或相关的对象实例的延续。
createBoshHandler()
- private void createBoshHandler(ContextHandlerCollection contexts, String boshPath)
- {
- ServletContextHandler context = new ServletContextHandler(contexts, boshPath, ServletContextHandler.SESSIONS);
- context.addServlet(new ServletHolder(new HttpBindServlet()),"/*");
- }
createCrossDomainHandler()
- private void createCrossDomainHandler(ContextHandlerCollection contexts, String crossPath)
- {
- ServletContextHandler context = new ServletContextHandler(contexts, crossPath, ServletContextHandler.SESSIONS);
- context.addServlet(new ServletHolder(new FlashCrossDomainServlet()),"/crossdomain.xml");
- }
loadStaticDirectory()
最后一步:
- httpBindServer.start()
Script Syntax(脚本语法)
介绍
一些运行时环境的跨域安全限制,允许客户端访问纯XML文本,只有当它接收到一个特定的服务器(例如,Web客户端的主机名下载)。出人意料的是,同样的环境通常允许客户端接收和执行来自任何服务器的脚本。安全注意事项以下部分描述了重大部署脚本语法风险
Script Syntax
1、Requesting Use of Script Syntax
BOSH的客户端可以发送一个BOSH连接管理器使用脚本语法,而不是纯粹的语法会话请求。如果连接管理器支持脚本语法,那么它必须发送它的会话创建响应使用脚本语法,并在会话中的所有后续客户端请求和连接管理器响应必须发送使用脚本语法。如果连接管理器没有支持“BOTH脚本”语法,那么它会给终端返回一个 'item-not-found' 或者HTTP404(未找到)来响应客户端的会话请求。
注意:HTTP响应的BODY在下面的例子中只包含换行符,以提高可读性。在实践中,必须是没有换行符。
例一:Script Syntax不支持绑定错误
- HTTP/1.1 200 OK
- Content-Type: text/javascript; charset=utf-8
- Cache-Control: no-store
- Cache-Control: no-cache
- Pragma: no-cache
- Content-Length: 212
- _BOSH_("<body type='terminate' condition='item-not-found'
- xmlns='http://jabber.org/protocol/httpbind'/>")
例二:Script Syntax不支持http错误
HTTP/1.1 404 Not Found
Content-Length: 0
2.变更请求语法
客户端必须进行以下更改他们的请求转换脚本语法:
1.Certain字节的UTF-8编码的<body/>元素,根据字节内定义的URI由RFC3986[3]为逃避规则。因此,所有的八位位组,除了那些代表7位字母数字字符或字符 - _〜!$&'()*+,=:@/?应被取代与字符三重峰,组成的百分比字符由两个16进制码表示的八位位组的值的“%
2.A'?'字符和URI编码<body/>元素,必须附加到URI连接管理器内运行其服务器。
3 URI必须在HTTP GET请求发送到连接管理器。
4.Include额外的HTTP标头,以防止请求/响应缓存或存储任何中介。
注:“GET”和“1.1”在HTTP GET标题行下面的两个例子中之间的所有空白只包括以提高可读性。在实践中不能有空格。
例3:请求BOSH会话脚本语法
- GET /webclient?%3Cbody%20content='text/xml;%20charset=utf-8'%20
- hold='1'%20rid='1573741820'%20to='jabber.org'%20
- route='xmpp:jabber.org:9999'%20secure='true'%20ver='1.6'%20
- wait='60'%20xml:lang='en'%20
- xmlns='http://jabber.org/protocol/httpbind'/%3E
- HTTP/1.1
- Host: httpcm.jabber.org
- Accept-Encoding: gzip, deflate
- Cache-Control: no-store
- Cache-Control: no-cache
- Pragma: no-cache
- Content-Length: 0
例4:脚本语法传输节点
- GET /webclient?%3Cbody%20rid='1249243562'%20sid='SomeSID'%20
- xmlns='http://jabber.org/protocol/httpbind'%3E%3C
- message%20to='friend@example.com'%20xmlns='jabber:client'%3E%3C
- body%3EI%20said%20%22Hi!%22%3C/body%3E%3C/message%3E%3C/body%3E
- HTTP/1.1
- Host: httpcm.jabber.org
- Accept-Encoding: gzip, deflate
- Cache-Control: no-store
- Cache-Control: no-cache
- Pragma: no-cache
- Content-Length: 0
虽然2616不限制长度的HTTP URIs中,可能会限制客户端的运行时环境,它可以包括在每个GET请求的URI长度。[4]在这种情况下,客户端必须减少的<body/>元素的内容,并在随后的HTTP GET请求包裹在新的<body/>元素(与递增'远离'属性)发送的其它的内容。这是可能的,因为不像纯语法,脚本语法的连接管理器必须把一串字符之间的打开和关闭每个请求的<BODY>标签的字节流的一部分,而不是作为一套完整的XML节。任何一个<body/>元素的内容必须不能被解析其余的流隔离。
Changes to the Response Syntax
连接管理器必须进行以下更改他们的反应,转换脚本语法:
1.Certain字符必须更换内的<body/>元素的根据规则的ECMAScript定义的字符串内转义字符。必要的替换概述于下表。
表1:字符替换
- 字符
- Unicode代码点值
- 转义序列
- " U+0022 \"
- Line Feed (New Line) U+000A \n
- Carriage Return U+000D \r
- Line Separator U+2028 \u2028
- Paragraph Separator U+2029 \u2029
- \ U+005C \\
每个Unicode格式控制字符(即字符类别“CF”在UNICODE字符数据库,例如,左到右的商标或从右到左标记)也必须被取代它的Unicode转义序列(例如\u200e\ u200f)
2。下面的八个字符必须追加到的<body/>元素:
_BOSH_("
3,下面的两个字符必须附加到的<body/>元素:
")
4如果客户端请求不拥有'内容'属性,那么HTTP响应的Content-Type头必须是“文/ JavaScript中的字符集= UTF-8”或“应用程序/x-javascript的字符集= UTF-8“。
5.Include额外的HTTP标头,以防止缓存或存储任何中介。
注:在下面的两个例子的HTTP响应的尸体仅包括所有的换行都以提高可读性。在实践中,必须是没有换行符。
Example 5. Session creation response in Script Syntax
HTTP/1.1200 OK
Content-Type: text/javascript; charset=utf-8
Cache-Control: no-store
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 233
_BOSH_("<body wait='60' inactivity='30' polling='5' requests='2'hold='1'
ack='1573741820'accept='deflate,gzip' maxpause='120' sid='SomeSID'
charsets='ISO_8859-1 ISO-2022-JP'ver='1.6' from='jabber.org'
secure='true'xmlns='http://jabber.org/protocol/httpbind'/>")
(转)OpenFire源码学习之十二:HttpBind&Script Syntax的更多相关文章
- (转)OpenFire源码学习之十:连接管理(上)
转:http://blog.csdn.net/huwenfeng_2011/article/details/43415827 关于连接管理分为上下两部分 连接管理 在大并发环境下,连接资源 需要随着用 ...
- (转)OpenFire源码学习之十八:IOS离线推送
转:http://blog.csdn.net/huwenfeng_2011/article/details/43458213 IOS离线推送 场景: 如果您有iOS端的APP,在会话聊天的时候,用户登 ...
- 【js】 vue 2.5.1 源码学习(十二)模板编译
大体思路(十) 本节内容: 1. baseoptions 参数分析 2. options 参数分析 3. parse 编译器 4. parseHTNL 函数解析 // parse 解析 parser- ...
- (转)OpenFire源码学习之十五:插件开发
转:http://blog.csdn.net/huwenfeng_2011/article/details/43418493 Plugin接口规范 插件是openfire功能的增强表现,它的主要任务: ...
- (转)OpenFire源码学习之十四:插件管理
转:http://blog.csdn.net/huwenfeng_2011/article/details/43418433 Plugin管理 Openfire把插件模块加入到容器分为以下步骤: l ...
- yii2源码学习笔记(十二)
继续了解controller基类. /** * Runs a request specified in terms of a route.在路径中指定的请求. * The route can be e ...
- Alamofire源码解读系列(十二)之请求(Request)
本篇是Alamofire中的请求抽象层的讲解 前言 在Alamofire中,围绕着Request,设计了很多额外的特性,这也恰恰表明,Request是所有请求的基础部分和发起点.这无疑给我们一个Req ...
- libevent源码深度剖析十二
libevent源码深度剖析十二 ——让libevent支持多线程 张亮 Libevent本身不是多线程安全的,在多核的时代,如何能充分利用CPU的能力呢,这一节来说说如何在多线程环境中使用libev ...
- hbase源码系列(十二)Get、Scan在服务端是如何处理
hbase源码系列(十二)Get.Scan在服务端是如何处理? 继上一篇讲了Put和Delete之后,这一篇我们讲Get和Scan, 因为我发现这两个操作几乎是一样的过程,就像之前的Put和Del ...
随机推荐
- zju1610Count the Colors
ZOJ Problem Set - 1610 Count the Colors Time Limit: 2 Seconds Memory Limit: 65536 KB Painting s ...
- php下载
生成迅雷下载链接 $url = "http://www.xxx.com/xxx/test.jpg"; echo "thunder://".base64_enco ...
- HTML5: HTML5 Canvas
ylbtech-HTML5: HTML5 Canvas 1.返回顶部 1. HTML5 Canvas <canvas> 标签定义图形,比如图表和其他图像,您必须使用脚本来绘制图形. 在画布 ...
- 建立logback.xml 配合MDC 实现追踪
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false ...
- 72、salesforce call RESTful 的方式
通过Chrome的Postman 来call salesforce的restful api https://login.salesforce.com/services/oauth2/token?gra ...
- Android毕业四年升P8,年收入超100w,他是如何做到的?
很多人从事Android开发工作多年,走过的弯和坎,不计其数,经历的心酸难与外人道也.相信大家感触最深的还是:选择大于努力.选择正确的方向,才能够走的更远,更踏实. 今天我来分享一下自己心得体会,并没 ...
- 13-vim-复制和粘贴-01-复制和粘贴
1.vi中提供有一个被复制文本的缓冲区 复制命令会将选中的文字保存在缓冲区. 删除命令删除的文字会被保存在缓冲区 在需要的位置,使用粘贴命令可以将缓冲区的文字插入到光标所在位置. vi中的文本缓冲区同 ...
- PAT程序设计
VS2013中自行对齐的快捷键操作: CTRL+K+F 1.定义二维数组 ]=]; 2.绝对值函数 int abs(int i) 返回整型参数i的绝对值 double cabs(struct comp ...
- ArrayList的几种初始化方法
1.使用Arrays.asList方法 ArrayList<Object> obj = new ArrayList<Object>(Arrays.asList(Object o ...
- IDEA webapp文件夹不识别解决方案
使用IDEA 创建moudule 用的是的是maven archertype-quickstart ,自动生成并么有webapp目录,于是我从别的项目中拷贝了一个,发现webapp文件夹图标和普通文件 ...