设为首页 收藏本站
查看: 715|回复: 0

[经验分享] [Tomcat] 基于Coyote的HTTP 1.1协议连接器

[复制链接]

尚未签到

发表于 2015-8-9 12:54:24 | 显示全部楼层 |阅读模式
1. 模块架构
  org.apache.coyote.http11包支持http1.1协议,内部分为三类:ARP、NIO、普通http,这里只对最基本的普通http(使用java的IO流,而非NIO流)作简单研究。
  这个包主要有以下几个类:


  • Http11Protocol,实现了ProtocolHandler接口
  • Http11Processor,实现了ActionHook接口
  • InternalInputBuffer,实现了InputBuffer接口
  • InternalOutputBuffer,实现了OutputBuffer接口
  • InputFilter和OutputFilter接口,具体的实现类在 org.apache.coyote.http11.filters 中。
  架构图如下所示(转自王程斯的博客):
DSC0000.png
  处理流程:


  • JIOEndpoint起到一个连接池的作用,可以启动多个socket监听,一旦收到浏览器发来的请求后,把对应的socket对象通过process方法,传递给Http11ConnectionHandler,再交给Http11Processor
  • Http11Processor内部有个InternalInputBuffer(图上未画出),InternalInputBuffer是真正对socket中包含的字节流进行处理的,它将字节转换为Request
  • Request流经过滤器filters,最后到达实现了Adapter接口的容器,模块的工作就到此为止,回头继续处理下一个socket

2. 代码研究


  • Http11Protocol
  该类是http1.1协议的ProtocolHandler实现,主要包含了内部类Http11ConnectionHandler和Http11ConnectionHandler的实例对象,它的初始化代码和过程如下:



public Http11Protocol() {
endpoint = new JIoEndpoint(); //新建endpoint,启动若干socket server,监听服务器端口
cHandler = new Http11ConnectionHandler(this); //协议连接处理对象,用于对socket连接的处理
((JIoEndpoint) endpoint).setHandler(cHandler); //一旦endpoint接收到请求,会将对应socket实例传给cHandler.process方法进行处理
        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
}
  Http11ConnectionHandler内部类则继承了AbstractConnectionHandler,它主要实现了createProcessor方法,用于将Http11Processor应用于连接处理流程中。函数内新建了一个Http11Processor实例,并将该实例绑定到ConnectionHandler上。ConnectionHandler一旦接收到从endpoint发来的处理请求,使用对应的Processor对接收到的数据进行处理,形成Request对象。
  2. Http11Processor
  这个类的作用就是生成Request(当然本质上还是InternalInputBuffer完成的),交给实现了Adapter接口的容器。它有adapter、request、response、inputbuffer、outputbuffer等几个关键字段,还有很多和http 1.1协议有关的字段和方法,用于协议的解析(这里就不对解析过程进行分析了)。
  这个类对socket对象依次做如下的处理:
  1)        把socket的inputstream和outputstream分别与inputbuffer和outputbuffer关联起来
  2)        通过inputBuffer.parseRequestLine() 和 inputBuffer.parseHeaders() 方法,解析socket字节流中的头字段,写到request中
  3)        通过prepareRequest方法组装filter,用于处理http消息体
  4)        adapter.service(request, response) 把生成的request和response交给容器处理
  5)        如果一切顺利,开始处理socket中的下一个请求(因为http1.1是支持持续连接的,所以一个socket中可能包含多个请求),循环回到第一步
  6)        如果出错,则设置response的响应码,并终止循环
  其中的prepareRequest方法,是用于准备inputbuffer的filter,主要包括一下几个过程:
  1)        根据之前对http头字段的解析,分别检查protocol、method、expect、user-agent和MIMEheaders,此外还检查URI的格式
  2)        准备加载filter
  3)        如果有transfer-encoding这个头字段,则分别设置不同编码的filter
  4)        校验content-length头字段
  3. InternalInputBuffer
  这个类的主要功能是:从socket中获取字节流,将字节读入一个缓冲区buf,然后从缓冲区逐个解析http请求头以及内容。
  主要的字段有:
  request:Request对象,从缓冲区中解析出的信息会写入request中
  buf:缓冲区,从socket的inputstream读取的字节放入此缓冲区中
  headers : MimeHeaders,保存以键值对出现的报头,也就是除去请求报文第一行之后的所有头部
  主要的方法有:
  parseRequestLine()
  解析请求报头的第一行,形如:GET http://class/download.microtool.de:80/somedata.exe,包括请求方法(GET or POST)、协议(http)、URI。解析后,放入request中
  parseHeader()
  解析刚才parseRequestLine()之后的报头,由于RequestLine之后的报头都是以“:”分隔的键值对,因此每执行一次本方法,则在headers 中加入一个键值对,如果格式错误则返回false
  endRequest()
  结束一个request的处理,把多余的字节清空
  nextRequest()
  准备下一个request的处理,这个方法主要用来对所有的标记位和指针进行复位
  fill()
  从socket的inputstream中读出一定数量的字节,填充buf,在很多方法中都有用到。例如解析报头时,当发现buf已经读取完了,就调用fill重新填充buf,如果inputstream已经读完了,fill返回false。
  4. InternalOutputBuffer
  这个类是用来从response中读取信息,然后写入socket的outputstream中,返回给客户端的。里面的很多方法和InternalInputBuffer基本相似,有两个是专门用于处理Response的:nextRequest()和endRequest()。这两个函数的功能主要是在当前Request处理完并发出Response之后,跳转到下一个Request的处理或者结束处理。

3. org.apache.coyote.http11.upgrade
  Apache在基于coyote的HTTP 1.1连接器实现模块中还实现了能够供基于HTTP 1.1的一些协议和在HTTP 1.1基础上进行操作的接口和实现,方便进行扩展。它主要有以下几个类:


  • UpgradeInbound接口
  接口定义了基于socket数据流处理需要实现的一些接口,主要功能是当连接器从socket中读取出数据后,会通知UpgradeInbound实现类进行数据解析,即onData函数。  
  2. UpgradeProcessor类
  这个类是基于HTTP 1.1连接器的upgrade连接器Processor的模板类,定义了一个标准的UpgradeProcessor必须要重写的读写处理函数:



// Output methods
public abstract void flush() throws IOException;
public abstract void write(int b) throws IOException;
public abstract void write(byte[] b, int off, int len) throws IOException;
// Input methods
public abstract int read() throws IOException;
public abstract int read(boolean block, byte[] bytes, int off, int len)
throws IOException;
  3. UpgradeOutbound类
  该类继承了OutputStream类,重写了write函数。这个类是一个功能封装类,在类初始化的时候传入用于解析数据的UpgradeProcessor,而在重写的write函数中则直接调用Processor的处理函数,使得数据能够被写到Upgraded的数据流中。
  
  参考材料:
  http://blog.iyunv.com/wangchengsi/article/details/2995536

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-96393-1-1.html 上篇帖子: CentOS下yum安装mysql,jdk以及tomcat 下篇帖子: 在Tomcat中配置404自定义错误页面全解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表