一.计算机网络体系结构
OSI体系结构 | TCP/IP体系结构 | 五层体系结构 |
---|---|---|
应用层 | 应用层(HTTP) | 应用层 |
表示层 | ||
会话层 | ||
传输层 | 传输层(TCP) | 传输层 |
网络层 | 网络层(IP) | 网络层 |
数据链路层 | 网络接口层 | 链路层 |
物理层 | 物理层 |
低三层为通信子网,负责数据传输
高三层为资源子网,相当于计算机系统,完成数据处理;
传输层承上启下
TCP/IP各层的功能如下:
二.TCP协议
Transmission Control Protocol,即:传输控制协议
属于传输层通信协议
基于TCP的应用层协议有HTTP、SMTP、FTP、Telnet 和 POP3;
a.三次握手
所谓的三次握手即TCP连接的建立,这个连接必须是一方主动打开,另一方被动打开的。建立过程如下:
握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:
①.首先客户端向服务器端发送一段TCP报文,其中:
标记位为SYN,表示“请求建立新连接”;
序号为seq=x(x一般为1);
随后客户端进入SYN-SENT阶段;
②.服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:
标志位为SYN和ACK,表示“确认客户端的报文seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
序号为seq=y;
确认号为ack=x+1,表示收到客户端的序号seq并将其值加1作为自己确认号ack的值;随后服务器端进入SYN-RCVD阶段。
③.客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:
标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);
序号为seq=x+1,表示收到服务器端的确认号ack,并将其值作为自己的序号值;
确认号为ack=y+1,表示收到服务器端序号seq,并将其值加1作为自己的确认号ack的值;
随后客户端进入ESTABLISHED阶段。
服务器收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。
在客户端与服务器端传输的TCP报文中,双方的确认号ack和序号seq的值,都是在彼此ack和seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。
此后客户端和服务器端进行正常的数据传输。这就是“三次握手”的过程。
a.1.为什么要三次握手?
防止服务器端因接收了早已失效的连接请求报文,从而一直等待客户端请求,最终导致形成死锁、浪费资源。
可以这样理解:“第三次握手”是客户端向服务器端发送数据,这个数据就是要告诉服务器,客户端有没有收到服务器“第二次握手”时传过去的数据。若发送的这个数据是“收到了”的信息,接收后服务器就正常建立TCP连接,否则建立TCP连接失败,服务器关闭连接端口。由此减少服务器开销和接收到失效请求发生的错误。
a.2.通俗理解为什么不是二次握手?
假定A向B发送一个连接请求,由于一些原因,导致A发出的连接请求在一个网络节点逗留了比较多的时间。此时A会将此连接请求作为无效处理,又重新向B发起了一次新的连接请求,B正常收到此连接请求后建立了连接,数据传输完成后释放了连接。如果此时A发出的第一次请求又到达了B,B会以为A又发起了一次连接请求,如果是两次握手:此时连接就建立了,B会一直等待A发送数据,从而白白浪费B的资源。 如果是三次握手:由于A没有发起连接请求,也就不会理会B的连接响应,B没有收到A的确认连接,就会关闭掉本次连接。
b.四次挥手
所谓四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放。释放过程如下:
①.首先客户端想要释放连接,向服务器端发送一段TCP报文,其中:
标记位为FIN,表示“请求释放连接“;
序号为seq=u;随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文。
②.服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:
标记位为ACK,表示“接收到客户端发送的释放连接的请求”;
序号为seq=v;
确认号为ack=u+1,表示是在收到客户端报文的基础上,将其序号seq值加1作为本段报文确认号ack的值;
随后服务器端开始准备释放服务器端到客户端方向上的连接。客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段。
前"两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了。
③.服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:
标记位为FIN,ACK,表示“已经准备好释放连接了”。注意:这里的ACK并不是确认收到服务器端报文的确认报文。
序号为seq=w;确认号为ack=u+1;表示是在收到客户端报文的基础上,将其序号seq值加1作为本段报文确认号ack的值。
随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向 上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
④.客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:
标记位为ACK,表示“接收到服务器准备好释放连接的信号”。
序号为seq=u+1;表示是在收到了服务器端报文的基础上,将其确认号ack值作为本段报文序号的值。
确认号为ack=w+1;表示是在收到了服务器端报文的基础上,将其序号seq值作为本段报文确认号的值。
随后客户端开始在TIME-WAIT阶段等待2MSL。
服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。
客户端等待完2MSL之后,结束TIME-WAIT阶段,进入CLOSED阶段,由此完成“四次挥手”。
后“两次挥手”既让客户端知道了服务器端准备好释放连接了,也让服务器端知道了客户端了解了自己准备好释放连接了。于是,可以确认关闭服务器端到客户端方向上的连接了,由此完成“四次挥手”。
与“三次握手”一样,在客户端与服务器端传输的TCP报文中,双方的确认号ack和序号seq的值,都是在彼此ack和seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性,一旦出现某一方发出的TCP报文丢失,便无法继续"挥手",以此确保了"四次挥手"的顺利完成。
c.为什么“握手”是三次,“挥手”却要四次
TCP建立连接时之所以只需要"三次握手",是因为在第二次"握手"过程中,服务器端发送给客户端的TCP报文是以SYN与ACK作为标志位的。SYN是请求连接标志,表示服务器端同意建立连接;ACK是确认报文,表示告诉客户端,服务器端收到了它的请求报文。
即SYN建立连接报文与ACK确认接收报文是在同一次"握手"当中传输的,所以"三次握手"不多也不少,正好让双方明确彼此信息互通。
TCP释放连接时之所以需要“四次挥手”,是因为FIN释放连接报文与ACK确认接收报文是分别由第二次和第三次"握手"传输的。为何建立连接时一起传输,释放连接时却要分开传输?
建立连接时,被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备,可以直接返回SYN和ACK报文,开始建立连接。
释放连接时,被动方服务器突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。
所以是“三次握手”,“四次挥手”。
d.为什么客户端在TIME-WAIT阶段要等2MSL
为了确认服务器端是否收到客户端发出的ACK确认报文。
当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。
MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。
服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;
如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;
如果客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。
所以,客户端要经历时长为2SML的TIME-WAIT阶段;这也是为什么客户端比服务器端晚进入CLOSED阶段的原因。
三.HTTP协议
HTTP协议属于应用层,采用请求->响应的工作方式,半双工工作模式(可以发,可以收,不能同时),长/短连接(http1.1默认是长连接,http1.0是短连接)工作方式如下:
请求的报文结构如下:
HTTP1.1 与 HTTP1.0的区别
Http1.1 比 Http1.0 多了以下优点:
1.引入持久连接,即在同一个TCP的连接中可传送多个HTTP请求 & 响应,即在http头加入了Connection:Keep-Alive,加入Connection:close才关闭;
2.多个请求 & 响应可同时进行、可重叠
3.引入更加多的请求头 & 响应头,如 与身份认证、状态管理 & Cache缓存等机制相关的、HTTP1.0无host字段
网络连接类型
类型 | 特点 | 应用 |
---|---|---|
单工 | 在通信过程的任意时刻,信息只能由一方A传到另一方B | 无线广播,数据只能从发送端传输到接收端 |
半双工 | 在任意时刻,信息既可以由A传到B,又能由B传到A, 但只能由一个方向上的传输存在,称为半双工传输 |
Http协议 同一时刻数据只能单向流动,客户端想服务端请 求数据或服务器想客户端响应数据 |
全双工 | 在任意时刻,线路上存在A到B和B到A的双向信号传输 | Socket协议、websocket协议、电话 socket协议是支持全双工的,发送数据的同时 也可以接受数据 |
Https通信流程
一个Https请求实际上包含了两次http传输,可以细分为8步:
1.客户端向服务器发送Https请求,连接到服务器的443端口;
2.服务器端有一个密钥对,即公钥和私钥,服务器端保存着私钥,不能将其泄露,公钥可以发给任何人;
3.服务器发送了一个SSL证书给客户端,SSL证书中包含的具体内容为:证书的发布机构CA、证书的有效期、公钥、证书所有者、签名;
4.客户端收到服务器端的SSL证书之后,会验证服务器发送的数字证书的合法性,如果发现证书有问题,那么Https传输就无法继续;如果证书合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,然后用公钥对对称密钥进行加密,变成密文。至此,Https中的第一次Http请求结束;
5.客户端会发起Https中的第二次Http请求,将加密后的客户端密钥发送给服务器;
6.服务器接收到客户端发来的密文后,会用自己的私钥对其进行非对称解密,解密之后的明文就是对称密钥,然后用对称密钥对数据进行对称加密;
7.服务器将加密后的密文发送给客户端;
8.客户端收到服务器发送来的密文,用对称密钥对其进行对称解密,得到服务器发送的数据,这样Https中的第二次Http请求结束,整个Https传输完成。
Http与Https的区别
四.Socket
套接字,是应用层 与 TCP/IP 协议族通信的中间软件抽象层,表现为一个封装了 TCP / IP协议族 的编程接口(API)
1.Socket不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输);
2.通过Socket,我们才能在Andorid平台上通过 TCP/IP协议进行开发;
3.对用户来说,只需调用Socket去组织数据,以符合指定的协议,即可通信;
建立socket通信过程
Socket 与 Http 对比
Socket属于传输层,因为 TCP / IP协议属于传输层,解决的是数据如何在网络中传输的问题;
HTTP协议 属于 应用层,解决的是如何包装数据;
由于二者不属于同一层面,所以本来是没有可比性的。但随着发展,默认的Http里封装了下面几层的使用,所以才会出现Socket & HTTP协议的对比:(主要是工作方式的不同):
Http:采用请求->响应方式。
即建立网络连接后,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。可理解为:是客户端有需要才进行通信
Socket:采用服务器主动发送数据的方式
即建立网络连接后,服务器可主动发送消息给客户端,而不需要由客户端向服务器发送请求,可理解为:是服务器端有需要才进行通信
很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求, 不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。
心跳机制
正常连接断开客户端会给服务端发送一个fin包,服务端收到fin包后才会知道连接断开。 而断网断电时客户端无法发送fin包给服务端,所以服务端没办法检测到客户端已经断线。
为了缓解这个问题,服务端需要有个心跳逻辑,就是服务端检测到某个客户端多久没发送任何数据过来就认为客户端已经断开, 这需要客户端定时向服务端发送心跳数据维持连接。
心跳机制实现
长连接的实现:心跳机制,应用层协议大多都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线。并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议
1、在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。 系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。 而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。通过使用TCP的KeepAlive机制(修改那个time参数),可以让连接每隔一小段时间就产生一些ack包,以降低被踢掉的风险,当然,这样的代价是额外的网络和CPU负担。
2、应用层心跳机制实现。
Cookie与Session的作用和原理
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中。
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
Session:
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时就需要用某种机制来识具体的用户,这个机制就是Session。典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。
Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的。
具体到Web中的Session指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。因此从上述的定义中我们可以看到,Session实际上是一个特定的时间概念。
当客户端访问服务器时,服务器根据需求设置Session,将会话信息保存在服务器上,同时将标示Session的SessionId传递给客户端浏览器,浏览器将这个SessionId保存在内存中,我们称之为无过期时间的Cookie。浏览器关闭后,这个Cookie就会被清掉,它不会存在于用户的Cookie临时文件。以后浏览器每次请求都会额外加上这个参数值,服务器会根据这个SessionId,就能取得客户端的数据信息。
如果客户端浏览器意外关闭,服务器保存的Session数据不是立即释放,此时数据还会存在,只要我们知道那个SessionId,就可以继续通过请求获得此Session的信息,因为此时后台的Session还存在,当然我们可以设置一个Session超时时间,一旦超过规定时间没有客户端请求时,服务器就会清除对应SessionId的Session信息。
Cookie
Cookie是由服务器端生成,发送给User-Agent(一般是web浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用Cookie)。Cookie名称和值可以由服务器端开发自己定义,对于JSP而言也可以直接写入Sessionid,这样服务器可以知道该用户是否合法用户以及是否需要重新登录等。
五.网络安全
在前面讲到,Https在通信过程中用到了非对称加密及服务端会发送ssl证书给客户端,客户端需要验证证书的合法性,然后进行下一次通信。
1.非对称加密
即公钥公开给任何人,私钥自己保留,用公钥加密,用私钥解密,用一张图来形象的表示非对称加密:
2.消息摘要/数字证书/CA
Https在通信过程中客户端收到服务端的SSL证书后,会验证其合法性,关于数字证书生成及验证流程,用一张图来表示一下工作过程:
3.中间人攻击
中间人攻击(Man-in-the-Middle attack:MITM)是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,实际上整个会话都被攻击者完全控制。
本文学习参考了以下文章:
https://www.jianshu.com/p/45d27f3e1196
https://baijiahao.baidu.com/s?id=1654225744653405133&wfr=spider&for=pc