网络
Web
当在浏览器输入URL后,整个网络请求的生命周期:
解析地址
浏览器向 DNS 服务器请求解析 URL 中的域名所对应的 IP 地址;
建立连接
根据解析出的
IP
地址与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接发送HTTP请求
通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
返回HTTP响应
Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,并把对应的 html 文本发送给浏览器,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
释放TCP连接
若
connection
模式为close
,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection
模式为keepalive
,则该连接会保持一段时间,在该时间内可以继续接收请求。客户端解析内容
客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
TCP
三次握手(Three-way Handshake)
建立起一个TCP连接需要经过“三次握手”:
第一次握手(SYN=1, seq=x)
客户端发送一个 TCP 的 SYN 标志位置1的包(syn=j),指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里,客户端进入进入SYN_SEND状态,等待服务器确认。
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)
服务器收到syn包,必须确认客户的SYN(ack=j+1),同时发回确认包(ACK)应答,即 SYN 标志位和 ACK 标志位均为1的SYN+ACK包(syn=k)。
服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。
第三次握手(ACK=1,ACKnum=y+1)
客户端收到服务器的SYN+ACK包,再次向服务器发送确认包ACK(ack=k+1),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1,此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
三次握手的目的是连接服务器指定端口,建立TCP
连接,并同步连接双方的序列号和确认号,交换TCP
窗口大小信息。在 socket 编程中,客户端执行 connect() 时,将触发三次握手。
“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”,解决“网络中存在延迟的重复分组”的问题。
握手过程中传送的包里不包含数据,“三次握手”完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
“三次握手”本质是为了满足“在不可靠信道上可靠地传输信息”这一需求所导致的。如果信道是可靠的,即无论什么时候发出消息,对方一定能收到,或者你不关心是否要保证对方收到你的消息,那就能像UDP那样直接发送消息就可以了。
四次分手
断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次分手”:
第一次分手(FIN=1,seq=x)
假设客户端想要关闭连接,设置Sequence Number和Acknowledgment Number,向服务端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。发送完毕后,客户端进入 FIN_WAIT_1 状态。
第二次分手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,向客户端发回一个ACK报文段的确认包,Acknowledgment Number为Sequence Number加1,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
第三次分手(FIN=1,seq=y) 服务器端准备好关闭连接时,向客户端发送结束连接请求(FIN报文段),FIN 置为1。发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。
第四次分手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求(FIN报文段),向服务端发送一个确认包(ACK报文段),并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到客户端的确认包(ACK报文段)之后,关闭连接,进入 CLOSED 状态。
客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。
HTTP
HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范。。
TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。WEB使用HTTP协议作应用层协议,以封装HTTP 文本信息,然后使用TCP/IP做传输层协议将它发到网络上。
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即使不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
HTTP的三次握手,其实就是使用三次TCP握手确认建立一个HTTP连接。
HTTPS
HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
客户端发起HTTPS请求
客户端发送一个 ClientHello 消息到服务器端,消息中同时包含了它的 Transport Layer Security (TLS) 版本,可用的加密算法和压缩算法。
传送证书
服务器端向客户端返回一个 ServerHello 消息,消息中包含了服务器端的 TLS 版本,服务器所选择的加密和压缩算法,以及数字证书认证机构(Certificate Authority,缩写 CA)签发的服务器公开证书,证书中包含了公钥。客户端会使用这个公钥加密接下来的握手过程,直到协商生成一个新的对称密钥。证书中还包含了该证书所应用的域名范围(Common Name,简称 CN),用于客户端验证身份。
客户端解析证书
客户端根据自己的信任 CA 列表,验证服务器端的证书(公钥)是否有效、可信。比如颁发机构,过期时间等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果认为可信,客户端会生成一串伪随机数,使用服务器的公钥加密它。这串随机数会被用于生成新的对称密钥
传送加密信息 客户端将使用证书加密后的随机值发送给服务端,服务端得到这个随机值后,客户端和服务端的通信就可以通过这个随机值来进行加密解密了。
服务端解密信息 服务端接收到客户端传过来的随机值(私钥),使用自己的私钥解密此随机数,然后使用这串随机数生成自己的对称主密钥
传输加密后的信息
客户端发送一个 Finished 消息给服务器端,使用对称密钥加密这次通讯的一个散列值
服务器端生成自己的 hash 值,然后解密客户端发送来的信息,检查这两个值是否对应。如果对应,就向客户端发送一个 Finished 消息,也使用协商好的对称密钥加密
从现在开始,接下来整个 TLS 会话都使用对称秘钥进行加密,传输应用层(HTTP)内容。
从上面的过程可以看到,TLS 的完整过程需要三个算法(协议),密钥交互算法,对称加密算法,和消息认证算法(TLS 的传输会使用 MAC(message authentication code) 进行完整性检查)。
HTTPS 过程中很重要的一个步骤,是服务器需要有 CA 颁发的证书,客户端根据自己的信任 CA 列表验证服务器的身份。现代浏览器中,证书验证的过程依赖于证书信任链。
所谓证书信任链,即一个证书要依靠上一级证书来证明自己是可信的,最顶层的证书被称为根证书,拥有根证书的机构被称为根 CA。
SOCKET
Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。从设计模式的角度看来,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
Socket 还可以认为是一种网络间不同计算机上的进程通信的一种方法,利用三元组(ip地址,协议,端口)就可以唯一标识网络中的进程,网络中的进程通信可以利用这个标志与其它进程进行交互。
Socket 起源于 Unix ,Unix/Linux 基本哲学之一就是“一切皆文件”,都可以用“打开(open) –> 读写(write/read) –> 关闭(close)”模式来进行操作。因此 Socket 也被处理为一种特殊的文件。
套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。
是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket。
套接字之间的连接过程分为三个步骤:
服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。
由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网 络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。
而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。
很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数 据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。TCP(Transmission Control Protocol) 传输控制协议