1、TCP 协议详解为什么会有 TCP/IP 协议在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别。就好像圣经中上帝打乱了各地人的口音,让他们无法合作一样。计算机使用者意识到,计算机只是单兵作战并不会发挥太大的作用。只有把它们联合起来,电脑才会发挥出它最大的潜力。于是人们就想方设法的用电线把电脑连接到了一起。但是简单的连到一起是远远不够的,就好像语言不同的两个人互相见了面,完全不能交流信息。因而他们需要定义一些共通的东西来进行交流,TCP/IP 就是为此而生。TCP/IP 不是一个协议,而是一个协议族的统称。里面包括了 IP 协议
2、,IMCP 协议,TCP 协议,以及我们更加熟悉的 http、ftp、pop3 协议等等。电脑有了这些,就好像学会了外语一样,就可以和其他的计算机终端做自由的交流了。TCP/IP 协议分层!TCP 分层 2.jpg(http:/upload-images.jianshu.io/upload_images/2964446-94da7e7442050d15.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)TCP/IP 协议族按照层次由上到下,层层包装。应用层:向用户提供一组常用的应用程序,比如电子邮件、文件传输访问、远程登录等。远程登录
3、 TELNET 使用 TELNET 协议提供在网络其它主机上注册的接口。TELNET 会话提供了基于字符的虚拟终端。文件传输访问 FTP 使用 FTP 协议来提供网络内机器间的文件拷贝功能。传输层:提供应用程序间的通信。其功能包括:一、格式化信息流;二、提供可靠传输。为实现后者,传输层协议规定接收端必须发回确认,并且假如分组丢失,必须重新发送。网络层 :负责相邻计算机之间的通信。其功能包括三方面。一、处理来自传输层的分组发送请求,收到请求后,将分组装入 IP 数据报,填充报头,选择去往信宿机的路径,然后将数据报发往适当的网络接口。二、处理输入数据报:首先检查其合法性,然后进行寻径-假如该数据报
4、已到达信宿机,则去掉报头,将剩下部分交给适当的传输协议;假如该数据报尚未到达信宿,则转发该数据报。三、处理路径、流控、拥塞等问题。网络接口层:这是 TCP/IP 软件的最低层,负责接收 IP 数据报并通过网络发送之,或者从网络上接收物理帧,抽出 IP 数据报,交给 IP 层。IP 是无连接的IP 用于计算机之间的通信。IP 是无连接的通信协议。它不会占用两个正在通信的计算机之间的通信线路。这样,IP 就降低了对网络线路的需求。每条线可以同时满足许多不同的计算机之间的通信需要。通过 IP,消息(或者其他数据)被分割为小的独立的包,并通过因特网在计算机之间传送。IP 负责将每个包路由至它的目的地。
5、IP 地址每个计算机必须有一个 IP 地址才能够连入因特网。每个 IP 包必须有一个地址才能够发送到另一台计算机。网络上每一个节点都必须有一个独立的 Internet 地址(也叫做 IP 地址)。现在,通常使用的 IP 地址是一个 32bit 的数字,也就是我们常说的 IPv4 标准,这32bit 的数字分成四组,也就是常见的 255.255.255.255 的样式。IPv4 标准上,地址被分为五类,我们常用的是 B 类地址。具体的分类请参考其他文档。需要注意的是 IP 地址是网络号+主机号的组合,这非常重要。CP/IP 使用 32 个比特来编址。一个计算机字节是 8 比特。所以 TCP/IP
6、 使用了 4 个字节。一个计算机字节可以包含 256 个不同的值:00000000、00000001、00000010、00000011、00000100、00000101 、00000110、00000111 、00001000 . 直到 11111111。现在,你知道了为什么 TCP/IP 地址是介于 0 到 255 之间的 4 个数字。TCP 使用固定的连接TCP 用于应用程序之间的通信。当应用程序希望通过 TCP 与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方“握手”之后,TCP 将在两个应用程序之间建立一个全双工 (full-duplex) 的
7、通信。这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止。UDP 和 TCP 很相似,但是更简单,同时可靠性低于 TCP。IP 路由器当一个 IP 包从一台计算机被发送,它会到达一个 IP 路由器。IP 路由器负责将这个包路由至它的目的地,直接地或者通过其他的路由器。在一个相同的通信中,一个包所经由的路径可能会和其他的包不同。而路由器负责根据通信量、网络中的错误或者其他参数来进行正确地寻址。域名12 个阿拉伯数字很难记忆。使用一个名称更容易。用于 TCP/IP 地址的名字被称为域名。 就是一个域名。当你键入一个像 http:/ 这样的域名,域名会被一种 DNS 程序翻译
8、为数字。在全世界,数量庞大的 DNS 服务器被连入因特网。DNS 服务器负责将域名翻译为 TCP/IP 地址,同时负责使用新的域名信息更新彼此的系统。当一个新的域名连同其 TCP/IP 地址一同注册后,全世界的 DNS 服务器都会对此信息进行更新。TCP/IPTCP/IP 意味着 TCP 和 IP 在一起协同工作。TCP 负责应用软件(比如你的浏览器)和网络软件之间的通信。IP 负责计算机之间的通信。TCP 负责将数据分割并装入 IP 包,然后在它们到达的时候重新组合它们。IP 负责将包发送至接受者。TCP 报文格式TCP 报文格式 1.jpg16 位源端口号:16 位的源端口中包含初始化通信
9、的端口。源端口和源 IP 地址的作用是标识报文的返回地址。16 位目的端口号:16 位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。32 位序号:32 位的序列号由接收端计算机使用,重新分段的报文成最初形式。当 SYN 出现,序列码实际上是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是 ISN+1。这个序列号(序列码)可用来补偿传输中的不一致。32 位确认序号:32 位的序列号由接收端计算机使用,重组分段的报文成最初形式。如果设置了 ACK 控制位,这个值表示一个准备接收的包的序列码。4 位首部长度: 4 位包括 TCP
10、头大小,指示何处数据开始。保留(6 位): 6 位值域,这些位必须是 0。为了将来定义新的用途而保留。标志:6 位标志域。表示为:紧急标志、有意义的应答标志、推、重置连接标志、同步序列号标志、完成发送数据标志。按照顺序排列是:URG、ACK、PSH 、RST、SYN、FIN。16 位窗口大小:用来表示想收到的每个 TCP 数据段的大小。 TCP 的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个 16字节字段,因而窗口大小最大为 65535 字节。16 位校验和:16 位 TCP 头。源机器基于数据内容
11、计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP 报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。16 位紧急指针:指向后面是优先数据的字节,在 URG 标志设置了时才有效。如果 URG 标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。选项:长度不定,但长度必须为 1 个字节。如果没有选项就表示这个 1 字节的域等于 0。数据:该 TCP 协议包负载的数据。在上述字段中,6 位标志域的各个选项功能如下。URG:紧急标志。紧急标志为 “1“表明该位有效。ACK:确认标志。表明确认编号栏有效。大多数情况下该
12、标志位是置位的。TCP 报头内的确认编号栏内包含的确认编号(w+1 )为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。PSH:推标志。该标志置位时,接收端不将该数据进行队列处理,而是尽可能快地将数据转由应用处理。在处理 Telnet 或rlogin 等交互模式的连接时,该标志总是置位的。RST:复位标志。用于复位相应的 TCP 连接。SYN:同步标志。表明同步序列编号栏有效。该标志仅在三次握手建立 TCP 连接时有效。它提示 TCP 连接的服务端检查序列编号,该序列编号为 TCP 连接初始端(一般是客户端)的初始序列编号。在这里,可以把 TCP 序列编号看作是一个范围从0 到 4
13、,294,967,295 的 32 位计数器。通过 TCP 连接交换的数据中每一个字节都经过序列编号。在 TCP 报头中的序列编号栏包括了 TCP 分段中第一个字节的序列编号。FIN:结束标志。TCP 三次握手所谓三次握手(Three-Way Handshake)即建立 TCP 连接,就是指建立一个TCP 连接时,需要客户端和服务端总共发送 3 个包以确认连接的建立。在socket 编程中,这一过程由客户端执行 connect 来触发,整个流程如下图所示:TCP 三次握手.png(1)第一次握手: Client 将标志位 SYN 置为 1,随机产生一个值 seq=J,并将该数据包发送给 Ser
14、ver,Client 进入 SYN_SENT 状态,等待 Server 确认。(2)第二次握手: Server 收到数据包后由标志位 SYN=1 知道 Client 请求建立连接,Server 将标志位 SYN 和 ACK 都置为 1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给 Client 以确认连接请求,Server 进入SYN_RCVD 状态。(3)第三次握手: Client 收到确认后,检查 ack 是否为 J+1,ACK 是否为 1,如果正确则将标志位 ACK 置为 1,ack=K+1 ,并将该数据包发送给Server,Server 检查 ack 是否为 K+1,A
15、CK 是否为 1,如果正确则连接建立成功,Client 和 Server 进入 ESTABLISHED 状态,完成三次握手,随后 Client与 Server 之间可以开始传输数据了。简单来说,就是1、建立连接时,客户端发送 SYN 包(SYN=i )到服务器,并进入到 SYN-SEND 状态,等待服务器确认2、服务器收到 SYN 包,必须确认客户的 SYN(ack=i+1),同时自己也发送一个 SYN 包( SYN=k),即 SYN+ACK 包,此时服务器进入 SYN-RECV 状态3、客户端收到服务器的 SYN+ACK 包,向服务器发送确认报ACK(ack=k+1),此包发送完毕,客户端和
16、服务器进入 ESTABLISHED 状态,完成三次握手,客户端与服务器开始传送数据。SYN 攻击:在三次握手过程中,Server 发送 SYN-ACK 之后,收到 Client 的 ACK 之前的TCP 连接称为半连接(half-open connect),此时 Server 处于 SYN_RCVD 状态,当收到 ACK 后,Server 转入 ESTABLISHED 状态。SYN 攻击就是 Client在短时间内伪造大量不存在的 IP 地址,并向 Server 不断地发送 SYN 包,Server 回复确认包,并等待 Client 的确认,由于源地址是不存在的,因此,Server 需要不断重
17、发直至超时,这些伪造的 SYN 包将产时间占用未连接队列,导致正常的 SYN 请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN 攻击时一种典型的 DDOS 攻击,检测 SYN 攻击的方式非常简单,即当Server 上有大量半连接状态且源 IP 地址是随机的,则可以断定遭到 SYN 攻击了,使用如下命令可以让之现行:#netstat -nap | grep SYN_RECVTCP 四次挥手所谓四次挥手(Four-Way Wavehand)即终止 TCP 连接,就是指断开一个TCP 连接时,需要客户端和服务端总共发送 4 个包以确认连接的断开。在socket 编程中,这一过程由客户端或
18、服务端任一方执行 close 来触发,整个流程如下图所示:TCP 四次挥手.png由于 TCP 连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个 FIN 来终止这一方向的连接,收到一个 FIN 只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个 TCP 连接上仍然能够发送数据,直到这一方向也发送了 FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。(1)第一次挥手: Client 发送一个 FIN,用来关闭 Client 到 Server 的数据传送,Client 进入 FIN_WAIT_1 状
19、态。(2)第二次挥手: Server 收到 FIN 后,发送一个 ACK 给 Client,确认序号为收到序号+1(与 SYN 相同,一个 FIN 占用一个序号),Server 进入CLOSE_WAIT 状态。(3)第三次挥手: Server 发送一个 FIN,用来关闭 Server 到 Client 的数据传送,Server 进入 LAST_ACK 状态。(4)第四次挥手: Client 收到 FIN 后,Client 进入 TIME_WAIT 状态,接着发送一个 ACK 给 Server,确认序号为收到序号+1 ,Server 进入 CLOSED 状态,完成四次挥手。为什么建立连接是三次握
20、手,而关闭连接却是四次挥手呢?这是因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把ACK 和 SYN 放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即 close,也可以发送一些数据给对方后,再发送 FIN 报文给对方来表示同意现在关闭连接,因此,己方 ACK 和 FIN一般都会分开发送。为什么 TIME_WAIT 状态需要经过 2MSL(最大报文段生存时间) 才能返回到 CLOSE 状态?原因有二:一、保证 TCP 协议的全双工连接能够可靠关闭二、保证
21、这次连接的重复数据段从网络中消失先说第一点,如果 Client 直接 CLOSED 了,那么由于 IP 协议的不可靠性或者是其它网络原因,导致 Server 没有收到 Client 最后回复的 ACK。那么 Server就会在超时之后继续发送 FIN,此时由于 Client 已经 CLOSED 了,就找不到与重发的 FIN 对应的连接,最后 Server 就会收到 RST 而不是 ACK,Server 就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致 TCP 协议不符合可靠连接的要求。所以,Client 不是直接进入CLOSED,而是要保持 TIME_WAIT,当
22、再次收到 FIN 的时候,能够保证对方收到 ACK,最后正确的关闭连接。再说第二点,如果 Client 直接 CLOSED,然后又再向 Server 发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为 TCP 协议判断不同连接的依据是 socket pair,于是,TCP 协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以 TCP 连接还要在TIME_WAIT 状态等待 2 倍 MSL,这样可以保证本次连接的所有数据都从网络中消失。