前言
tomcat是常用的Web 应用服务器,目前国内有很多文章讲解了tomcat架构,请求流程等,但是没有如何解析http请求及如何解决TCP粘包拆包,所以这篇文章的目的就是介绍这块内容,一下内容完全是个人查看tomcat nio 相关源码来总结的,源码版本9.0.30,欢迎提问,欢迎指出错误。
请求解析
参数在请求行时的请求形式
GET /myServlet?name=zhangsan HTTP/1.1
Connection: keep-alive
参数在请求体时的请求形式
POST /myServlet HTTP/1.1
Connection: keep-alive
name=zhangsan
中间有一个空行表示请求头和请求体的分界。
解析请求行
以 GET /myServlet?name=zhangsan HTTP/1.1为例
将请求行按空格进行分割,将method(POST),requestURI(/myServlet ),protocol(HTTP/1.1 )存起来
将?之后的数据存入queryString(name=zhangsan)存起来。
一直遇见换行符解析结束。
解析请求头
以这个为例
Content-Length: 13
Connection: keep-alive
name=zhangsan
解析过程很简单,以":"进行分割,一直到读取到一个只有换行符的空行,请求头解析结束。
解析请求体
请求体解析是通过请求头中的Content-Length来进行解析的,读取Content-Length值中对应的字节数。
如何解决拆包粘包
知道了请求结果和解析流程,下面就介绍一下怎样处理拆包粘包。
粘包
粘包的解决是非常简单的,比如粘包后是这样的数据。
POST /myServlet?name=liuhao HTTP/1.1
Content-Length: 13
name=zhangsan
POST /myServlet?name=liuhao HTTP/1.1
tomcat处理请求时根据Content-Length进行读取,是不会读到第二个请求的,如果没有Content-Length的话也就没有请求体,请求头和下一个请求有空行,也不会读取。
拆包
拆包的处理方式大致相同就是数据没有读取完成就等
请求行拆包
POST /myServlet?name=liuh
请求行拆包,请求行结束的标志是换行符,如果没有收到换行符,表示请求行没有解析完,这个时候会重新监听读事件(使用java nio selector),之前的数据会放到buffer中缓存。
请求头拆包
POST /myServlet?name=liuhao HTTP/1.1
Content-Type:
请求头拆包,请求头结束的标志是空行,如果没有只有换行符的空行,表示请求行没有解析完,这个时候会重新监听读事件(使用java nio selector),之前的数据会放到buffer中缓存。
请求体拆包
POST /myServlet HTTP/1.1
Content-Length: 13
Connection: keep-alive
name=
请求体拆包,请求体结束的标志是数据读取足够的字节数,如果读取不够,会阻塞的读取数据直到读取成功或超时报错。
源码阅读指南
将tomcat的源码导入到IDE,然后从架构和原理来了解tomcat,之后可以通过阅读其他博客来了解源码,最后自己在IDE中查看相关源码,如果看的吃力,可以debug来看,如果想看拆包解包的源码,可以用postman发送一个完整的http请求,然后使用telnet来进行拆包粘包测试,也可以写一个client来测试,不过有一点要注意,telnet每次回车时会将 传过去,需要在debug的时候去除,如果写一个client的话也要注意这一点。