一、简介
TCP、UDP、HTTP、HTTPS 都是通信协议,也就是通信时所遵守的规则,只有双方按照这个规则“说话”,对方才能理解或为之服务。
二、TCP、UDP、HTTP、HTTPS 之间的关系
TCP/IP 是个协议组,可分为四个层次:网络接口层、网络层、传输层和应用层。
在网络层,有 IP 协议、ICMP 协议、ARP 协议、RARP 协议等。
在传输层,有 TCP 协议与 UDP 协议。
在应用层,有 WebSocket、FTP、HTTP、TELNET、SMTP、DNS 等协议。
而 HTTPS 可以理解为更安全的 HTTP 协议。
因此,TCP、UDP、HTTP、HTTPS 都是通信协议,只不过它们所在的层级不同,负责的工作也不同,并且 HTTP 是基于 TCP 实现的。
三、Socket 通信
Socket 是为了实现以上的通信过程而建立成来的通信管道,其真实的代表是客户端和服务器端的一个通信进程,双方进程通过 Socket 进行通信,而通信的规则采用指定的协议。Socket 只是一种连接模式,不是协议。TCP、UDP,简单的说(虽然不准确)是两个基本的协议,很多其它协议都是基于这两个协议,如 HTTP 就是基于 TCP 的。用 Socket 可以创建 TCP 连接,也可以创建 UDP 连接,这意味着,用 Socket 可以创建任何协议的连接,因为其它协议都是基于此的。
四、TCP 协议
TCP 的建立连接协议又称之为“三次握手”:
第一次握手:建立连接时,客户端发送 SYN 包(syn=i)到服务器,并进入 SYN_SEND 状态,等待服务器确认。
第二次握手:服务器收到客户端发来的 SYN 包,必须对客户端进行确认 ACK (ack=i+1),同时服务器也发送一个 SYN 包(syn=j)到客户端,即服务器会发送 SYN+ACK 包,此时服务器进入 SYN_RECV 状态。
第三次握手:客户端收到服务器发送的 SYN+ACK 包,向服务器发送确认包 ACK(ack=j+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手。
为什么需要“三次握手”
第一个原因:初始化 Seq,TCP 通信是有序的,通信双方要通知对方自己的 Seq 值,也就是上图中的 X 和 Y,这个值要作为之后数据通信的序号,以保证应用层接受到数据不会因网络延时等原因而乱序,TCP 会用 Seq 来拼接数据。
第二个原因:在谢希仁版《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。这两种不同的表述其实阐明的是同一个问题。
谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:Client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 Server。本来这是一个早已失效的报文段。但 Server 收到此失效的连接请求报文段后,就误认为是 Client 再次发出的一个新的连接请求。于是就向 Client 发出确认报文段,同意建立连接。
假设不采用“三次握手”,那么只要 Server 发出确认,新的连接就建立了。由于现在 Client 并没有发出建立连接的请求,因此不会理睬 Server 的确认,也不会向 Server 发送数据。但 Server 却以为新的运输连接已经建立,并一直等待 Client 发来数据。这样,Server 的很多资源就白白浪费掉了。
“四次挥手”过程
由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向的连接。收到一个 FIN 只意味着这一方向上没有数据流动,而对方仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
- TCP 客户端发送一个 FIN,用来关闭客户到服务器的数据传送。
- 服务器收到这个 FIN,发回一个 ACK,确认序号为收到的序号加 1。和 SYN 一样,一个 FIN 将占用一个序号。
- 服务器关闭客户端的连接,发送一个 FIN 给客户端。
- 客户段发回 ACK 报文确认,并将确认序号设置为收到序号加1。
为什么需要“四次挥手”
那可能有人会有疑问,在 TCP 连接握手时为何 ACK 是和 SYN 一起发送,这里 ACK 却没有和 FIN 一起发送呢?
原因是因为 TCP 是全双工模式,接收到 FIN 时意味将没有数据再发来,但是还是可以继续发送数据。同时发送双方都需要发送 FIN 报文和 ACK 报文,加起来就是四次了。
TIME_WAIT 状态
在四次挥手的最后一次挥手中,主动断开方在发送最后一个 ACK 后,不能立刻关闭,而是需要等待 2MSL 后才能关闭,这是为什么呢?同时这也是面试中常提到的一个问题。原因如下:
假设发起主动关闭的一方(Client)最后发送的 ACK 在网络中丢失,由于 TCP 协议的重传机制,被动关闭的一方将会重发 FIN,在该 FIN 到达 Client之前,Client 必须维护这条连接状态,也就说这条 TCP 连接所对应的资源不能被立即释放或重新分配,直到另一方重发的 FIN 达到之后,Client 重发 ACK 后,经过 2MSL 时间周期没有再收到另一方的 FIN 之后,该 TCP 连接才能 CLOSED。
如果主动关闭一方不维护这样一个 TIME_WAIT 状态,那么当被动关闭一方重发的 FIN 到达时,主动关闭一方的 TCP 传输层会用 RST 包响应对方,这会被对方认为是有错误发生,然而这事实上只是正常的关闭连接过程,并非异常。
TCP 粘包拆包
TCP是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 把这些数据块仅仅看成一连串无结构的字节流,没有边界;另外从 TCP 的帧结构也可以看出,在 TCP 的首部没有表示数据长度的字段,基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。
粘包、拆包发生原因
发生TCP粘包或拆包有很多原因,现列出常见的几点:
- 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
- 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。
- 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
- 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
粘包、拆包解决办法
通过以上分析,我们清楚了粘包或拆包发生的原因,那么如何解决这个问题呢?解决问题的关键在于如何给每个数据包添加边界信息,常用的方法有如下几个:
1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
那么 UDP 是否会发生粘包或拆包的现象呢?
答案是:不会。UDP 是基于报文发送的,从 UDP 的帧结构可以看出,在 UDP 首部采用了 16bit 来指示 UDP 数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。
五、什么是HTTP协议
HTTP 全称是 HyperText Transfer Protocal,即:超文本传输协议。从1990 年开始就在 WWW 上广泛应用,是现今在 WWW 上应用最多的协议。HTTP 是应用层协议,当你上网浏览网页的时候,浏览器和 Web 服务器之间就会通过 HTTP 在 Internet 上进行数据的发送和接收。HTTP 是一个基于请求/响应模式的、无状态的协议,即我们通常所说的 Request/Response。
先看看请求(Request)报文:
请求(Request)报文 = 请求行 + 请求头 + 空行 + 请求体
请求行中包含请求方法,常见的请求方法有:
GET:获取资源,当前网络请求中,绝大部分使用的是 GET 方法。
POST:传输实体主体,POST 主要用来传输数据,而 GET 主要用来获取资源。
PUT:上传文件,由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。
DELETE:删除文件,与 PUT 功能相反,并且同样不带验证机制。
HEAD:获取报文首部,和 GET 方法类似,但是不返回报文实体主体部分。主要用于确认 URL 的有效性以及资源更新的日期时间等。
响应(Response)报文 = 状态行 + 响应头 + 空行 + 响应体
其中,状态行包含响应的状态,常见的状态如下:
1XX 信息
- 100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
2XX 成功
-
200 OK
-
204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
-
206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。
3XX 重定向
-
301 Moved Permanently :永久性重定向
-
302 Found :临时性重定向
-
303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
-
注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
-
304 Not Modified :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
-
307 Temporary Redirect :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
4XX 客户端错误
-
400 Bad Request :请求报文中存在语法错误。
-
401 Unauthorized :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
-
403 Forbidden :请求被拒绝。
-
404 Not Found
5XX 服务器错误
-
500 Internal Server Error :服务器正在执行请求时发生错误。
-
503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
HTTP 通信机制是在一次完整的 HTTP 通信过程中,Web 浏览器与 Web 服务器之间将完成下列7个步骤:
- 建立 TCP 连接
在 HTTP 工作开始之前,Web 浏览器首先要通过网络与 Web 服务器建立连接,该连接是通过 TCP 来完成的,该协议与 IP 协议共同构建 Internet,即著名的 TCP/IP 协议族,因此 Internet 又被称作是 TCP/IP 网络。HTTP 是比 TCP 更高层次的应用层协议,根据规则,只有低层协议建立之后才能,才能进行更层协议的连接,因此,首先要建立 TCP 连接,一般 TCP 连接的端口号是 80 - Web 浏览器向 Web 服务器发送请求命令
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。例如:GET/sample/hello.jsp HTTP/1.1
。 - Web 浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向 Web 服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。 - Web 服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答,HTTP/1.1 200 OK
,应答的第一部分是协议的版本号和应答状态码 - Web 服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。 - Web 服务器向浏览器发送数据
Web 服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type
应答头信息所描述的格式发送用户所请求的实际数据 - Web 服务器关闭 TCP 连接
一般情况下,一旦 Web 服务器向浏览器发送了请求数据,它就要关闭 TCP 连接,然后如果浏览器或者服务器在其头信息加入了这行Connection:keep-alive
,TCP 连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。
六、HTTPS 的工作原理
HTTPS 在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL 协议不仅仅是一套加密传输的协议,更是一件经过艺术家精心设计的艺术品,TLS/SSL 中使用了非对称加密、对称加密以及 HASH 算法。握手过程的具体描述如下:
- 浏览器将自己支持的一套加密规则发送给网站。
- 网站从中选出一组加密算法与 HASH 算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
- 浏览器获得网站证书之后浏览器要做以下工作:
a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示。
b) 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。
c) 使用约定好的 HASH 算法计算握手消息,并使用生成的随机数对消息进行加密,最后将之前生成的所有信息发送给网站。 - 网站接收浏览器发来的数据之后要做以下的操作:
a) 使用自己的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证 HASH 是否与浏览器发来的一致。
b) 使用密码加密一段握手消息,发送给浏览器。 - 浏览器解密并计算握手消息的 HASH,如果与服务端发来的 HASH 一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
简单的说:HTTPS 使用对称加密的方法通信,秘钥为 Key。但是为了安全的把秘钥 Key 发送给对方,于是在通信前,使用非对称加密的方法加密 Key。
这样做的目的是:非对称加密的安全性更强,但是加解密过程复杂耗时,对称加密的加解密过程简单,但安全性不强,于是 HTTPS 综合两种加密方式,既保证了安全性,又保证了效率。
HTTPS协议和HTTP协议的区别:
- HTTPS 协议需要到 ca 申请证书,一般免费证书很少,需要交费。
- HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
- HTTP和HTTPS使用的是完全不同的连接方式用的端口也不一样,前者是 80,后者是 443。
- HTTP 的连接很简单,是无状态的 。
- HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全。