TCP/IP协议

TCP/IP 协议的具体含义

从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议。实际生活当中有时也确实就是指这两种协议。然而在很多情况下,它只是利用 IP 进行通信时所必须用到的协议群的统称。具体来说,IP 或 ICMP、TCP 或 UDP、TELNET 或 FTP、以及 HTTP 等都属于 TCP/IP 协议。他们与 TCP 或 IP 的关系紧密,是互联网必不可少的组成部分。TCP/IP 一词泛指这些协议,因此,有时也称 TCP/IP 为网际协议群。
互联网进行通信时,需要相应的网络协议,TCP/IP 原本就是为使用互联网而开发制定的协议族。因此,互联网的协议就是 TCP/IP,TCP/IP 就是互联网的协议。

计算机网络体系结构分层

计算机网络体系结构分层

TCP/IP协议族按照层次由上到下,层层包装。最上面的是应用层,这里面有http,ftp,等等我们熟悉的协议。而第二层则是传输层,著名的TCP和UDP协议就在这个层次。第三层是网络层,IP协议就在这里,它负责对数据加上IP地址和其他的数据以确定传输的目标。第四层是数据链路层,这个层次为待传送的数据加入一个以太网协议头,并进行CRC编码,为最后的数据传输做准备。
img

上图清楚地表示了TCP/IP协议中每个层的作用,而TCP/IP协议通信的过程其实就对应着数据入栈与出栈的过程。入栈的过程,数据发送方每层不断地封装首部与尾部,添加一些传输的信息,确保能传输到目的地。出栈的过程,数据接收方每层不断地拆除首部与尾部,得到最终传输的数据。

img

IP协议

IP协议是TCP/IP协议的核心,所有的TCP,UDP,IMCP,IGMP的数据都以IP数据格式传输。要注意的是,IP不是可靠的协议,这是说,IP协议没有提供一种数据未传达以后的处理机制,这被认为是上层协议:TCP或UDP要做的事情。

IP地址

在数据链路层中我们一般通过MAC地址来识别不同的节点,而在IP层我们也要有一个类似的地址标识,这就是IP地址。

32位IP地址分为网络位和地址位,这样做可以减少路由器中路由表记录的数目,有了网络地址,就可以限定拥有相同网络地址的终端都在同一个范围内,那么路由表只需要维护一条这个网络地址的方向,就可以找到相应的这些终端了。

1
2
3
# A类IP地址: 0.0.0.0~127.0.0.0
# B类IP地址:128.0.0.1~191.255.0.0
# C类IP地址:192.168.0.0~239.255.255.0

IP协议头

img

这里只介绍:八位的TTL字段。这个字段规定该数据包在穿过多少个路由之后才会被抛弃。某个IP数据包每穿过一个路由器,该数据包的TTL数值就会减少1,当该数据包的TTL成为零,它就会被自动抛弃。
这个字段的最大值也就是255,也就是说一个协议包也就在路由器里面穿行255次就会被抛弃了,根据系统的不同,这个数字也不一样,一般是32或者是64。

传输层中的 TCP 和 UDP

TCP/IP 中有两个具有代表性的传输层协议,分别是 TCP 和 UDP。

他们的目标都是在程序之间传输数据。
数据可以是文本,文件,可以是视频,也可以是图片。对于TCP协议和UDP协议来说,都是一对二进制数,并没有多大的区别。

TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,当应用程序采用 TCP 发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端。TCP 为提供可靠性传输,实行“顺序控制”或“重发控制”机制。此外还具备“流控制(流量控制)”、“拥塞控制”、提高网络利用率等众多功能。

UDP 是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。在 UDP 的情况下,虽然可以确保发送消息的大小,却不能保证消息一定会到达。因此,应用有时会根据自己的需要进行重发处理。

TCP 和 UDP 的优缺点无法简单地、绝对地去做比较:TCP 用于在传输层有必要实现可靠传输的情况;而在一方面,UDP 主要用于那些对高速传输和实时性有较高要求的通信或广播通信。TCP 和 UDP 应该根据应用的目的按需使用。

TCPUDP之间的区别是什么?

最大的区别是一个基于连接,一个基于非连接。
我们来举一个简单的例子,如果把人与人的通信比喻为进程与进程的通信,我们基本有两种方式。第一种方式是写信,第二种方式是打电话。

image-20211105125454004

如果不考虑速度因素,这两种方式之间最大的区别是什么?就是信息出去之后,对方是否能收到以及收到的信内容是否完整。先后寄两封信过去,是否按照顺序接收
都变成了未知数,甚至你填写的收信地址和收信人是否存在,你都无法确认。
而打电话则不同,从拨打电话到对方接通,互相通话,再到结束通话后挂断。这一系列的流程都能得到及时的反馈,并且能确认对方准确的接收到。
打电话是基于连接的,也就是TCP,而写信就是基于非连接的,就是UDP。

TCP是如何保证以上过程的?

TCP协议

TCP报文数据包

img

img

TCP 首部各字段的意义和作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
TCP首部最小为20字节,这20字节分为5行,每行4个字节也就是32个位。

# 源端口和目的端口 Port

- 源端口号:16位的源端口中包含初始化通信的端口。源端口和源IP地址的作用是标识报文的返回地址。
- 目的端口号:16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。计算机通过端口号识别访问哪个服务,比如http服务或ftp服务,发送方端口号是进行随机端口,目标端口号决定了接收方哪个程序来接收 分别占用16位,也就是端口号最大是2^16,所以端口号的范围是0~65536

# 端口号的分配:

- 知名端口号一般位于:1 --- 255 之间
- 256 --- 1023的端口号,通常是由Unix系统占用(系统占用)
- 1024 ---5000 是大多数TCP、IP实现的临时分配
- 大于5000的一般是给其他服务预留的(Internet上并不常用的服务)

# 序号 Sequence Number

TCP用序列号对数据包进行标记,以便在到达目的地后重新重装,假设当前的序列号为 s,发送数据长度为 l,则下次发送数据时的序列号为 s + l。在建立连接时通常由计算机生成一个随机数作为序列号的初始值。

# 确认号 Acknowledgemt Number

4 个字节,表示期望收到对方下一个报文段的序号值。 TCP 的可靠性,是建立在「每一个数据报文都需要确认收到」的基础之上的。

就是说,通讯的任何一方在收到对方的一个报文之后,都要发送一个相对应的「确认报文」,来表达确认收到。 那么,确认报文,就会包含确认号。 例如,通讯的一方收到了第一个 25kb 的报文,该报文的 序号值=0,那么就需要回复一个确认报文,其中的确认号 = 25600.

# 数据偏移 Offset

0.5 个字节 (4 位)。 这个字段实际上是指出了 TCP 报文段的首部长度 ,它指出了 TCP报文段的数据起始处 距离 TCP报文的起始处 有多远。(注意 数据起始处 和 报文起始处 的意思)

一个数据偏移量 = 4 byte,由于 4 位二进制数能表示的最大十进制数字是 15,因此数据偏移的最大值是 60 byte,这也侧面限制了 TCP 首部的最大长度。

# 保留 Reserved

0.75 个字节 (6 位)。 保留为今后使用,但目前应置为 0

# 标志位 TCP Flags

标志位,一共有 6 个,分别占 1 位,共 6 位 。 每一位的值只有 01,分别表达不同意思。

- ACK:确认序号有效
- RST:重置连接
- SYN:发起了一个新连接
- FIN:释放一个连接

# 确认 ACK (Acknowlegemt)

当 ACK = 1 的时候,确认号(Acknowledgemt Number)有效。 一般称携带 ACK 标志的 TCP 报文段为「确认报文段」。为0表示数据段不包含确认信息,确认号被忽略。

TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 设置为 1

# 推送 PSH (Push)

当 PSH = 1 的时候,表示该报文段高优先级,接收方 TCP 应该尽快推送给接收应用程序,而不用等到整个 TCP 缓存都填满了后再交付。

# 复位 RST (Reset)

当 RST = 1 的时候,表示 TCP 连接中出现严重错误,需要释放并重新建立连接。 一般称携带 RST 标志的 TCP 报文段为「复位报文段」。

# 同步 SYN (SYNchronization)

当 SYN = 1 的时候,表明这是一个请求连接报文段。 一般称携带 SYN 标志的 TCP 报文段为「同步报文段」。 在 TCP 三次握手中的第一个报文就是同步报文段,在连接建立时用来同步序号。

对方若同意建立连接,则应在响应的报文段中使 SYN = 1 和 ACK = 1

# 终止 FIN (Finis)

当 FIN = 1 时,表示此报文段的发送方的数据已经发送完毕,并要求释放 TCP 连接。

一般称携带 FIN 的报文段为「结束报文段」。

在 TCP 四次挥手释放连接的时候,就会用到该标志。

# 窗口大小 Window Size

2 字节。

该字段明确指出了现在允许对方发送的数据量,它告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。 窗口大小的值是指,从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。

例如,假如确认号是 701 ,窗口字段是 1000。这就表明,从 701 号算起,发送此报文段的一方还有接收 1000 (字节序号是 701 ~ 1700) 个字节的数据的接收缓存空间。

# 校验和 TCP Checksum

2 个字节。 由发送端填充,接收端对 TCP 报文段执行 CRC 算法,以检验 TCP 报文段在传输过程中是否损坏,如果损坏这丢弃。

检验范围包括首部和数据两部分,这也是 TCP 可靠传输的一个重要保障。

# 紧急指针 Urgent Pointer

2 个字节。 仅在 URG = 1 时才有意义,它指出本报文段中的紧急数据的字节数。 当 URG = 1 时,发送方 TCP 就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。

因此,紧急指针指出了紧急数据的末尾在报文段中的位置。

有三个关键的步骤,分别为三次握手、传输确认、四次挥手。

TCP的三次握手,四次挥手

需要了解的信息

  • ACK : TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1
  • SYN(SYNchronization) : 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
  • FIN (finis)即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。

TCP(Transmission Control Protocol,传输控制协议)是 面向连接的协议,也就是说在收发数据之前,必须先和对方建立连接

一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,只简单的 描述下这三次对话的简单过程:主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;主机B向主机A发送同意连接和要求同步 (同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话;主机A再发出一个数据包确认主机B的要求同 步:“我现在就发,你接着吧!”,这是第三次对话。三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数 据。

TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换 TCP窗口大小信息。

img

三次握手

第一次握手: 建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;

第二次握手: 服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;

第三次握手: 客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

三次握手是建立连接的过程。当客户端向服务端发起连接时,会先发一包连接,请求数据过去询问一下能否与你建立连接。这包数据我们称之为SYN。
如果对端同意连接,则回复一包SYN+ACK包客户端收到之后回复一包ACK包,连接建立。
因为这个过程中互相发送了三包数据,所以称之为三次握手。

为什么要三次握手而不是两次握手?服务端回复完SYN+ACK之后就建立连接

为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

假设采用两次握手建立连接客户端,向服务端发送了一个SYN来请求建立连接。
因为某些未知的原因并没有到达服务器在中间某个网络节点产生了滞留。
为了建立连接客户端,会重发SYN,这次的数据包正常送达,服务端回复SYN+ACK之后建立起来连接。
但是第一包数据阻塞的网络节点突然恢复,第一包省包又送达到服务端。这时服务端会误认为是客户端又发起了一个新的连接,从而在两次握手之后进入等待数据状态。
服务端认为是两个连接,而客户端认为是一个连接,造成了状态不一致。
如果在三次握手的情况下,服务端收不到最后的ACK自然不会认为连接建立成功。
所以三次握手本质上来说就是为了解决网络信道不可靠的问题。为了能够在不可靠的信道上建立起可靠的连接。
经过三次握手之后,客户端和服务端都进入了数据传输状态。

具体例子:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

传输确认

TCP协议需要在不可靠的信道上保证可靠的连接。现在这有几个问题需要面对。

一包数据有可能会被拆成多包发送如何处理丢包问题?
这些数据包到达的先后顺序不同,如何处理乱序问题?

image-20211105132602749

针对这些要求,TCP协议为每一个连接建立了一个发送缓冲区。从建立连接后的第一个字节的序列号为零,后面每个字节的序列号就会增加一。
发送数据时,从发送缓冲区取一部分数据组成发送报文,在其TCP协议头中会附带序列号和长度。接收端在收到数据后需要回复确认报文。
确认报文中的ACK等于接收序列号加长度,也就是下一包数据需要发送的基础序列号。
这样一问一答的发送方式,能够使发送端确认发送的数据已经被对方收到。
发送端也可以一次发送连续的多包数据,接收端只需要回复一次ACK就可以了。
这样发送端可以把待发送的数据分割成一系列的碎片,发送到对端。对端根据序列号和长度在接收后重构出来完整的数据。
假设其中丢失了某些数据方在接收端可以要求发送端重传。比如丢失了100-199,这一百个字节接收端下发送端发送ACK=100的报文。
发送端收到后,重传这一包数据,接收端进行补齐。
以上过程不区分客户端和服务端,TCP连接是全双功能,对于两端来说均采用上述机制。


四次挥手

img

当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的啊。那对于TCP的断开连接,这里就有了神秘的“四次分手”。

第一次挥手: 主机1(可以使客户端,也可以是服务器端),设置Sequence Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;

第二次挥手: 主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;

第三次挥手: 主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;

第四次挥手: 主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。


处于连接状态的客户端和服务端都可以发起关闭连接请求。此时需要四次挥手来进行连接关闭。
假设客户端主动发起连接关闭请求,他需要将服务端发起一个FIN,表示要关闭连接自己,进入终止等待一状态。这是第一次挥手。
服务端收到FIN,发送一个ACK,表示自己进入了关闭等待状态,客户端进入终止等待状态,这是第二次挥手。
服务端此时还可以发送未发送的数据,而客户端还可以接收数据,待服务端发送完数据之后发送一个FIN,进入最后确认状态。这是第三次挥手。
客户端收到之后,回复ACK进入超时等待状态,经过超时时间后关闭连接。而服务端收到ACK,立即关闭连接,这是第四次挥手。

为什么要四次挥手

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么客户端需要等待超时时间?

这是为了保证对方已收到ACK。因为假设客户端发送完最后一包ACK后就释放了连接。一旦ACK在网络中丢失。服务端将一直停留在最后确认状态。

如果客户端发送最后一个ACK后等待一段时间,这时服务端因为没有收到ACK,会重发FIN。
客户端会响应这个分包重发ACK,用刷新超时时间这个机制跟三次握手一样,也是为了保证在不可靠的网络链路中进行可靠的连接,断开确认。

UDP协议

UDP协议是基于非连接的发送数据,就是简单的把数据包封装一下,然后从网卡发出去就可以了。数据包之间并没有状态上的联系。正因为UDP这种简单的处理方式,导致它的性能损耗非常少。对于CPU内存资源的占用也远小于TCP。但是对于网络传输过程中产生的丢包,UDP协议并不能保证。

img

什么时候应该使用TCP?

当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。

什么时候应该使用UDP?

UDP的优点是速度快,但是可能产生丢包。所以适用于对实时性要求较高,但是对少量丢包并没有太大要求的场景,比如域名查询与云通话、视频直播等。

常见协议

端口 服务 说明
21 FTP FTP 服务器所开放的端口,用于上传、下载
22 SSH 22 端口就是 ssh 端口,用于通过命令行模式远程连接 Linux 系统服务器
25 SMTP SMTP 服务器所开放的端口,用于发送邮件
80 HTTP 用于网站服务例如 IIS、Apache、Nginx 等提供对外访问
110 POP3 110 端口是为 POP3(邮件协议 3)服务开放的
137/138/139 NETBIOS 其中 137、138 是 UDP 端口,当通过网上邻居传输文件时用这个端口。而 139 端口:通过这个端口进入的连接试图获得 NetBIOS/SMB 服务。这个协议被用于 windows 文件和打印机共享和 SAMBA
143 IMAP 143 端口主要是用于“Internet Message AccessProtocol”v2(Internet 消息访问协议,简称 IMAP),和 POP3 一样,是用于电子邮件的接收的协议
443 HTTPS 网页浏览端口,能提供加密和通过安全端口传输的另一种 HTTP
1433 SQL Server 1433 端口,是 SQL Server 默认的端口,SQL Server 服务使用两个端口:TCP-1433、UDP-1434。其中 1433 用于供 SQL Server 对外提供服务,1434 用于向请求者返回 SQL Server 使用了哪个 TCP/IP 端口
3306 MySQL 3306 端口,是 MySQL 数据库的默认端口,用于 MySQL 对外提供服务
3389 Windows Server Remote Desktop Services 3389 端口是 Windows 远程桌面的服务端口,可以通过这个端口,用 “远程桌面” 等连接工具来连接到远程的服务器
8080 代理端口 8080 端口同 80 端口,是被用于 WWW 代理服务的,可以实现网页浏览,经常在访问某个网站或使用代理服务器的时候,会加上 “:8080” 端口号。另外 Apache Tomcat web server 安装后,默认的服务端口就是 8080