传输控制协议TCP

TCP主要特点 :

  • 面向连接的运输层协议

  • 每一条TCP连接只能有2个端点, TCP是点对点的

  • 提供可靠交付

  • 全双工通信

  • 面向字节流

 

TCP的工作流程

TCP字节流

TCP的连接

TCP连接的端点叫套接字(socket)

socket = (IP地址 : 端口号)

每一条TCP连接唯一地被通信两端的两个端点(socket)所确定. 即 :
TCP连接 ::= {socket1, socket2} = {(IP1 : port1), (IP2 : port2)}

TCP报文段的首部

 TCP报文段的首部

  • 源端口和目的端口 : 同UDP端口作用

  • 序号 : 本报文段的数据的第一个字节的序号

  • 确认号 : 期望收到对方下一个报文段的第一个数据字节的序号
    若确认号 = N, 则表明 : 到序号N-1为止的所有数据都已正常收到

  • 数据偏移 : TCP报文段的首部长度

  • 保留 : 以后用, 目前为0

  • 紧急URG : 若URG = 1时, 说明紧急指针字段有效, 告诉系统这是紧急数据, 应尽快传送. 例如突然要中断传送

  • 确认ACK : ACK = 1时确认号才有效, ACK = 0时确认号无效. TCP规定, 连接建立后所有传送的报文段都必须把ACK置1

  • 推送PSH : 若PSH = 1, 则接收方收到报文段之后不再等到整个缓存满而是直接向上交付

  • 复位RST : 当RST = 1, 说明TCP连接有严重错误, 必须释放连接再重连

  • 同步SYN : 在连接建立时用来同步序号. 当SYN = 1, ACK = 0时表明这是一个连接请求报文段, 对方若同意建立连接, 则在响应的报文段中置SYN = 1, ACK = 1

  • 终止FIN : 当FIN = 1, 表明此报文段的发送方数据已发送完毕, 并要求释放连接

  • 窗口 : 告诉对方 : 从本报文段首部中的确认号算起, 接收方目前允许对方发送的数据量. 这是作为接收方让发送方设置其发送窗口的依据

  • 检验和 : 同UDP, 检验首部和数据部分

  • 紧急指针 : 当URG = 1时有效, 指出紧急数据的末尾在报文段的位置

  • 选项 : 最大可40字节, 没有则为0
    最大报文段长度MSS(Maximum Segment Size) : 每一个TCP报文段中数据字段的最大长度, 若不填写则为默认的536字节.

 

窗口

TCP中很重要的一个概念, 那就是窗口(发送窗口和接收窗口)

窗口

由于停止等待协议非常低效, 于是衍生出窗口这一概念. 上图为发送方维持的发送窗口, 位于发送窗口的5个分组都可以连续发送出去而不需要等待对方的确认. 每收到一个确认, 就把发送窗口前移一个分组的位置. 这大大提高了信道利用率!

接收方不必发送每个分组的确认报文, 而是采用累积确认的方式. 也就是说, 对按序到达的最后一个分组发送确认报文.

超时重传

如果发送方等待一段时间后, 还是没收到 ACK 确认报文, 就会启动超时重传. 这个等待的时间为重传超时时间(RTO, Retransmission TimeOut).

然而, RTO 的值不是固定的, 这个时间总是略大于连接往返时间(RTT,Round Trip Time). 假设报文发送过去需要5秒, 对方收到后发送确认报文回来也需要5秒, 那么RTT就为10秒, 那这RTO就要比10秒要略大一些. 那么超过RTO之后还没有收到确认报文就认为报文丢失了, 就要重传.

流量控制

利用滑动窗口和报文段的发送时机来进行流量控制.

拥塞控制

发送方维持一个拥塞窗口cwnd, 发送窗口 = 拥塞窗口.

慢开始 : cwnd = 1, 然后每经过一个传输轮次就翻倍
拥塞避免 : 让cwnd缓慢增大, 每经过一个传输轮次就+1
慢开始门限ssthresh :

当cwnd < ssthresh, 使用慢开始算法
当cwnd > ssthresh, 使用拥塞避免算法
当cwnd = ssthresh, 随意

拥塞控制

只要判断网络出现拥塞, 把ssthresh设为当前发送拥塞窗口的一半(不能小于2), 并把cwnd设为1, 重新执行慢开始算法.

除了慢开始和拥塞避免算法外, 还有一组快重传和快恢复算法 :

快重传 : 接收方及时发送确认, 而发送方只要一连收到三个重复确认, 马上重传
快恢复 : 当发送方一连收到三个重复确认时, ssthresh减半, cwnd设为ssthresh.

TCP三次握手

TCP三次握手建立连接和四次挥手断开连接是面试爱问的知识点.

TCP三次握手

Q : 为什么要三次握手, 两次不可以吗?

A : 试想一下, A第一次发送请求连接, 但是在网络某节点滞留了, A超时重传, 然后这一次一切正常, A跟B就愉快地进行数据传输了. 等到连接释放了以后, 那个迷失了的连接请求突然到了B那, 如果是两次握手的话, B发送确认, 它们就算是建立起了连接了. 事实上A并不会理会这个确认, 因为我压根没有要传数据啊. 但是B却傻傻地以为有数据要来, 苦苦等待. 结果就是造成资源的浪费.

更加接地气的解释就是 : A打电话给B

第一次握手 : 你好, 我是A, 你能听到我说话吗
第二次握手 : 听到了, 我是B, 你能听到我说话吗
第三次握手 : 听到了, 我们可以开始聊天了

三次握手其实就是为了检测双方的发送和接收能力是否正常, 你说呢?

TCP四次挥手

TCP四次挥手

Q : 为什么要四次挥手, 而不是两次, 三次?

A :
首先, 由于TCP的全双工通信, 双方都能作为数据发送方. A想要关闭连接, 必须要等数据都发送完毕, 才发送FIN给B. (此时A处于半关闭状态)
然后, B发送确认ACK, 并且B此时如果要发送数据, 就发送(例如做一些释放前的处理)
再者, B发送完数据之后, 发送FIN给A. (此时B处于半关闭状态)
然后, A发送ACK, 进入TIME-WAIT状态
最后, 经过2MSL时间后没有收到B传来的报文, 则确定B收到了ACK了. (此时A, B才算是处于完全关闭状态)

PS : 仔细分析以上步骤就知道为什么不能少于四次挥手了.

Q : 为什么要等待2MSL(Maximum Segment Lifetime)时间, 才从TIME_WAIT到CLOSED?

A : 在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

更加接地气的解释 :

第一次挥手 : A告诉B, 我没数据发了, 准备关闭连接了, 你要发送数据吗
第二次挥手 : B发送最后的数据
第三次挥手 : B告诉A, 我也要关闭连接了
第四次挥手 : A告诉B你可以关闭了, 我这边也关闭了

应用层

应用层协议最著名的就是HTTP, FTP了, 还有一个重要的DNS

域名系统(DNS, Domain Name System)

DNS 能将域名(例如, www.jianshu.com)解析成IP地址.

域名服务器分类

  • 根域名服务器 : 最高层次的域名服务器

  • 顶级域名服务器 : 如其名

  • 权限域名服务器 : 负责一个区的应服务器

  • 本地域名服务器 : 主机发送DNS查询请求就是发给它

 

DNS查询

DNS查询

  • 主机向本地域名服务器的查询一般都是采用递归查询

  • 本地域名服务器向根域名服务器的查询通常是采用迭代查询

    递归查询 : B问A广州怎么去, A不知道, A就问C, C不知道就问D...直到知道了再一层一层转告直到A告诉B. 
     迭代查询 : B问A广州怎么去, A不知道, A就告诉你可以去问C, 然后B就去问C, C不知道, C就告诉你可以去问D, 然后B就去问D...直到B知道为止
DNS查询例子 : 域名为x.tom.com的主机想知道y.jerry.com的IP地址
  • 主机x.tom.com先向本地域名服务器dns.tom.com进行递归查询

  • 本地域名服务器采用迭代查询. 它先问一个根域名服务器

  • 根域名服务器告诉它, 你去问顶级域名服务器dns.com

  • 本地域名服务器问顶级域名服务器dns.com

  • 顶级域名服务器告诉它, 你去问权限域名服务器dns.jerry.com

  • 本地域名服务器问权限域名服务器dns.jerry.com

  • 权限域名服务器dns.jerry.com告诉它所查询的主机的IP地址

  • 本地域名服务器把查询结果告诉主机x.tom.com

     

    PS : 该查询使用UDP, 并且为了提高DNS查询效率, 每个域名服务器都使用高速缓存.

URL

URL的格式 : <协议>://<主机>:<端口>/<路径>, 端口和路径有时可省略.

使用HTTP协议的URL : http://<主机>:<端口>/<路径>, HTTP默认端口号是80

HTTP协议

HTTP是面向事务的, 即它传输的数据是一个整体, 要么全部收到, 要么全部收不到.

万维网的工作过程

每一次HTTP请求就需要建立一次TCP连接和释放TCP连接.

HTTP是无连接, 无状态的. 每一次请求都是作为一次新请求.

HTTP/1.0 缺点 : 无连接, 每一次请求都要重新建立TCP连接, 所以每一次HTTP请求都要花费2倍RTT时间(一次TCP请求, 一次HTTP请求)

HTTP/1.1 : 使用持续连接, 即保持TCP连接一段时间.

HTTP/1.1持续工作的两种工作方式 : 非流水线方式和流水线方式
    非流水线方式 : 收到一个请求的响应再发下一个请求, 效率低, 浪费资源
    流水线方式 : 能够同时发送多个请求, 效率高
HTTP的GET和POST

GET 请求通常用于查询、获取数据,而 POST 请求则用于发送数据
GET 请求的参数在URL中, 因此绝不能用GET请求传输敏感数据, 而POST 请求的参数在请求头中, 安全性略高于GET请求

ps : POST请求的数据也是以明文的形式存放在请求头中, 因此也不安全

Cookie

万维网使用Cookie来跟踪用户, 表示HTTP服务器和用户之间传递的状态信息.

Cookie工作原理 :

1. 用户浏览某网站, 该网站的服务器为用户产生一个唯一的识别码, 并以此为索引在服务器后端数据库中产生一个项目2. 返回给用户的HTTP响应报文中添加一条 "Set-cookie", 值为该识别码, 如1233. 用户的浏览器将该cookie保存起来, 在用于继续浏览该网站时发送的每一个HTTP请求都会有一行 Cookie: 123

于是, 这个网站就知道Cookie为123的这个用户做了什么, 为这个用户维护一个独立的列表(如购物车)

当然, Cookie是把双刃剑, 方便的同时也带有危险性, 例如隐私泄露等, 用户可以自行决定是否使用Cookie

Session

Cookie是保存在客户端上的, 而Session是保存在服务器中. 当服务器收到用户发出的Cookie时, 会根据Cookie中的SessionID来查找对应的Session, 如没有则会生成一个新的SessionID返回给用户

总而言之, Cookie和Session就是同一样东西存放地方不同而已.

HTTPS

HTTPS协议

HTTPS协议在HTTP协议的基础上, 在HTTP和TCP中间加入了一层SSL/TLS加密层, 解决了HTTP不安全的问题: 冒充, 篡改, 窃听三大风险.