发表于: 2018-01-06 23:53:28
2 560
今天完成的事情:
什么是tcp/ip协议?TCP的三次握手指的是什么,为什么一定要三次握手,而不是四次或者是两次?
tcp/ip协议是TCP(传输控制协议)和IP(网际协议),提供点对点的链接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。它将软件通信过程抽象化为四个抽象层,采取协议堆栈的方式,分别实现出不同通信协议。协议族下的各种协议,依其功能不同,被分别归属到这四个层次结构之中。
TCP:面向连接的、可靠的字节流服务
在一个TCP连接中,仅有两方进行彼此通信。广播和多播不能用于TCP
TCP使用校验和,确认和重传机制来保证可靠传输
TCP给数据分节进行排序,并使用累积确认保证数据的顺序不变和非重复
所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
在自顶向下方法 3.5.6 TCP连接管理(中文第6版第169、170页)
三次握手:
使用java socket发送请求,打断点,debug模式
用wireshark进行抓包
可以看到三次TCP连接
1:A发,B收,B知道A能发
2:B发,A收,A知道B能发收
3:A发,B收,B知道A能收
为什么需要三次,因为双向验证,防止对失效请求,建立等待/连接,消耗资源。
A → B
A和B的地址 | SYN | A.seq=x |
seq=x 表示A向B发送的字节流的初始序号,实际上没有A. 这为了方便
SYN=1,ACK=0表示该报文段为连接请求报文。A端完成,进入SYN_SEND状态,看
B接收到:
B收到数据,B知道A能向自己发数据,而且知道了A发过来的字节流的初始序号。
B又设置了一下:A.seq+1 → B.ack=x+1, 表示B要告诉A我接收到了序号x的字节流,下一个字节流应该是x+1的。
B又自己初始化B.seq=y,表示自己作为服务端,发送字节流的初始序号。
B → A
把上边说的数据发送:
A和B的地址 | SYN ACK | B.ack=x+1 B.seq=y |
SYN=1,ACK=1表示该报文段为连接同意的应答报文。
B还进行了缓存,为建立连接做准备,进入SYN-RCVD状态。B端完成,等
A接收到报文:
A看到SYN ACK知道B同意连接。
A看到B.ack=x+1,知道B成功处理了自己的上一个字节流,也就是B可以接收。
A看到B.seq=y知道B也可以发送。
所以,A就设置了自己下一个字节流序号 B.seq+1(x+1) → A.ack
然后再设置下自己希望服务器发送的下一个字节流序号 B.seq+1(y+1) → A.seq
A → B
A和B的地址 | ACK | A.ack=x+1 A.seq=y+1 |
没有SYN了,SYN=0
B接收到数据,
看到A.ack=x+1 A.seq=y+1,说明A已经成功接收报文并做了处理。
那么就可以建立连接了。
三次握手这个说法不好,其实是双方各一次握手,各一次确认,其中一次握手和确认合并在一起。
这其中最要紧的就是 报文的验证(双向机制),如果我们设计一个单向验证的的通讯协议,那么就没有必要三次握手了。两次握手可以搞定这个协议。但是这个协议太浪费资源了。
springMVC
什么是servlet?
假如sun公司没有制定servlet规范,那我们怎么写服务端程序呢?
我们可以从0开始写socket,使用io从端口监听字节流,自己写好如何建连接,如何处理报文,如何发送报文,这些属于HTTP协议的最基础的操作。但是这一部分,sun公司已经写好了socket,我们可以直接用,当然你非要从头实现一遍,那真的就太厉害了。
所以java实现了socket,我们就可以看看怎么用这个socket来写一个客户端的请求:
并不是服务端处理请求的实现。
因为服务端比较复杂,但是原理类似。
最简单的大概步骤如下:首先构建一个请求.class、一个响应.class。再创建一个处理.class(参数包括上面的请求.class、响应.class,只处理一个http报文),然后创建一个web容器,请求过来后,使用这个处理class来处理,?谁来呢,应该是web容器?把字节流封装成请求.class传给处理.class,处理.class经过一系列操作,或者找到资源或者返回错误。把结果封装成响应.class,再把这个响应.class转换成响应报文传给请求者。
如果Sun公司不来规范,那么问题就很多了:
这些类包含哪些属性、哪些方法?web处理器和应用之间传递请求.class、响应.class时的时候怎么保证成功?把结果封装成响应.class的时候怎么封装?响应class转换成响应报文的时候也要开发者自己实现吗?
如果每个人实现都不同,那就太混乱了。所以出了Servlet规范,最少要知道 servlet、genericservlet、httpservlet:
所以可以这么总结:
sun公司写好了一堆处理http的接口,其他的(写web容器的、开发web应用的)要按照这个接口的规范来写。同时servlect还有一些封装,一些处理http的函数、方法。
servlet规范是一组接口,规定java web应用各个组件之间怎么通信交流。
而一个开发人员写出来,实例化的servlet,就是一个Java对象,这个对象拥有一系列的方法来处理HTTP请求。客户端发送一个HTTP请求,HTTP请求由Web容器分配给特定的Servlet进行处理,Web容器中包含了多个Servlet,特定的HTTP请求该由哪一个Servlet来处理是由Web容器(其实就是个servlet容器)中的web.xml来决定的。
那jsp又是什么呢?上面我们说要把响应.class转换成响应报文
这一步其实有很多问题:
响应.class 应该包含什么数据? 其实只要有html文件中那些 value就行了,其他的html标签、样式不应该放在响应.class中。
然后讨论转换:
直接写一个响应.class转换为响应报文的 方法,这样好吗?
这样太不直观了。比如说发响应报文(客户端接受到会转换成一个html网页),现在从数据库中取出的数据就是几个值,怎么办?难道手动写一个html文本,把这些值插入到对应的位置,然后发给客户端?不可能,这样开发者要崩溃。
这时又有好几种方案可供选择:一种叫html模版,一种就是jsp了,应该还有其他方法。这里单说jsp。
有了 jsp,我们又加了一层,并写了一个通用的方法来转化,具体来说:
把响应.class的数据,传给一个jsp文件(就是开发人员来编写jsp的过程)。转换的时候,用那个通用的方法,把jsp转为java类,再转为响应报文。
为什么有jsp转化为java类这一步?
可能是历史原因:原来是servlet对象转成响应报文,现在把jsp转为servlet(java 类),再转成响应报文。
总结如下:
jsp跑视图,servlet做逻辑控制。jsp本身就是一种模板化脚本化的servlet,用来优化html结构的编辑(如果不用jsp脚本标记标识的部分,在web容器转化时会被转换成out打印),servlet就是一个普通类,一旦编译加载后就不能动态替换。jsp的servlet应该是先经过jsp文件检测,如果有变化就重新生成相应的servlet源代码并编辑加载,没变化就沿用已编译好的源码。servlet一作为逻辑业务定下后一般不需要频繁改动,jsp作为界面输出倒是更频繁改动,而jsp的特性就是为这个设计的。
为何不用jsp代替servlet,运行速度,应为jsp要转换为servlet才算正式处理,转换要时间。
详细说下servlet
http://www.runoob.com/servlet/servlet-tutorial.html
http://blog.csdn.net/evankaka/article/details/45151569
先记下,后面再看。
明天计划的事情:
用原生servlet实现服务器,搞清楚servlet运行过程、springmvc 处理请求的过程(dispatchservlet)、深度思考、jetty服务器、maven部署
遇到的问题:
暂无
收获:
主要来看原理了,http协议太多了,一个月也看不完,准备看完深度思考相关的,就跳过去,再看看网上总结的。
评论