TCP/IP详解
TCP/IP并不是一个具体的协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇,只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
TCP/IP协议在一定程度上参考了OSI的体系结构,在TCP/IP协议中,它们被简化为了四个层次。
OSI七层模型 | TCP/IP概念层模型 | 功能 | TCP/IP协议族 |
---|---|---|---|
应用层 | 应用层 | 文件传输,电子邮件,文件服务,虚拟终端 | TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet |
表示层 | 数据格式化,代码转换,数据加密 | 没有协议 | |
会话层 | 解除或建立与别的接点的联系 | 没有协议 | |
传输层 | 传输层 | 提供端对端的接口 | TCP,UDP |
网络层 | 网络层 | 为数据包选择路由 | IP,ICMP,RIP,OSPF ,BCP,IGMP |
数据链路层 | 链路层 | 传输有地址的顿以及错误检测功能 | SLIP,CSLIP,PPP,ARP,RARP,MTU |
物理层 | 以二进制数据形式在物理媒体上传输数据 | ISO2110,IEEE802,IEEE802.2 |
数据链路层(以太网帧)
数据链路层与OSI参考模型中的物理层和数据链路层相对应。数据链路层是TCP/IP与各种LAN或WAN的接口。
数据链路层把数据封装成以太网数据包(packet)。一个数据包被称为一帧,制定这个规则的协议就是以太网协议。目前以太网帧有5种,交换机之间BPDU(桥协议数据单元)数据包使用的是IEEE802.3/LLC帧,其格式如下:
字段 | 长度(Byte) | 目的 |
---|---|---|
前导码(Preamble) | 7 | 0x55,一串1、0间隔,用于信号同步 |
帧开始符(SFD) | 1 | 1字节0xD5(10101011),表示一帧开始 |
目的MAC地址 | 6 | 指明帧的接受者 |
源MAC地址 | 6 | 指明帧的发送者 |
长度(Length)/类型(Type) | 2 | 0~1500保留为长度域值,1536~65535保留为类型域值(0x0600~0xFFFF) |
数据和填充(Data and Pad) | 46~1500 | 高层的数据,通常为3层协议数据单元。对于TCP/IP是IP数据包(注:如果帧长小于64字节,则要求“填充”,以使这个帧的长度达到64字节) |
帧校验序列(FCS) | 4 | 使用CRC计算从目的MAC到数据域这部分内容而得到的校验和 |
数据链路层的最大传输单元(Maximum Transmission Unit,MTU)是1500字节。当数据帧到达网卡时,在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和错,就丢弃此帧。因此,抓包软件抓到的是去掉前导同步码、帧开始分界符、FCS之外的数据,其最大值是6+6+2+1500=1514。
以太网规协议定,接入网络的设备都必须安装网络适配器,即网卡。数据包必须是从一块网卡传送到另一块网卡。 而网卡地址就是数据包的发送地址和接收地址,也就是帧首部所包含的MAC 地址,MAC 地址是每块网卡的身份标识,就如同我们身份证上的身份证号码,具有全球唯一性。 MAC地址采用十六进制标识,共6个字节, 前三个字节是厂商编号,后三个字节是网卡流水号,例如5D-3E-11-3F-05-E1。
有了MAC地址以后,以太网采用广播形式,把数据包发给该子网内所有主机,子网内每台主机在接收到这个包以后,都会读取首部数据中的目标MAC地址,然后和自己的MAC地址进行对比,如果相同就做下一步处理,如果不同,就丢弃这个包。
所以链路层的主要工作就是对电讯号进行分组并形成具有特定意义的数据帧,然后以广播的形式通过物理介质发送给接收方。
网络层(IP数据包)
网络层在TCP/IP协议中的位于第三层。
在TCP/IP协议中网络层可以进行网络连接的建立和终止以及IP地址的寻找等功能。
链路层提到定位唯一一个设备的方式是查询网卡地址。 那么在网络层要做的事情是:根据IP找到IP对应的设备。
网络通讯是基于IP协议来进行,MAC地址不具备规律性所以无法用来作为通讯协议,但是它是唯一的所以可以用来确定一台设备,IP地址目前有两个版本,分别是IPv4和IPv6。
IPv4是一个32位的地址,常采用4个十进制数字表示。 IP协议将这个32位的地址分为两部分,前面部分代表网络地址,后面部分表示该主机在局域网中的地址。 由于各类地址的分法不尽相同,以C类地址192.168.1.1为例,其中前24位就是网络地址,后8位就是主机地址。
因此,如果两个IP地址在同一个子网内,则网络地址一定相同。 为了判断IP地址中的网络地址,IP协议还引入了子网掩码, IP 地址和子网掩码通过按位与运算后就可以得到网络地址。
ARP协议
ARP(Address Resolution Protocol)地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址。ARP首先会发起一个请求数据包,数据包的首部包含了目标主机的IP地址,然后这个数据包会在链路层进行再次包装,生成以太网数据包,最终由以太网广播给子网内的所有主机,每一台主机都会接收到这个数据包,并取出标头里的IP地址,然后和自己的IP地址进行比较,如果相同就返回自己的MAC地址,如果不同就丢弃该数据包。 ARP接收返回消息,以此确定目标机的MAC地址;与此同时,ARP还会将返回的MAC地址与对应的IP地址存入本机ARP快取中并保留一定时间,下次请求时直接查询ARP快取以节约资源。
Route协议(路由协议)
通过ARP协议的工作原理可以发现,ARP 的 MAC 定址还是局限在同一个子网中,因此网络层引入了路由协议,首先通过 IP 协议来判断两台主机是否在同一个子网中,如果在同一个子网,就通过 ARP 协议查询对应的 MAC 地址,然后以广播的形式向该子网内的主机发送数据包;如果不在同一个子网,以太网会将该数据包转发给本子网的网关进行路由。 网关是互联网上子网与子网之间的桥梁,所以网关会进行多次转发,最终将该数据包转发到目标 IP 所在的子网中,然后再通过 ARP 获取目标机 MAC,最终也是通过广播形式将数据包发送给接收方。
而完成这个路由协议的物理设备就是路由器,在错综复杂的网络世界里,路由器扮演者交通枢纽的角色,它会根据信道情况,选择并设定路由,以最佳路径来转发数据包。
IP数据包
IP 数据报文由首部(称为报头)和数据两部分组成。首部的前一部分是固定长度,共 20 字节,是所有 IP 数据报必须具有的。所以,网络层的MTU=数据链路层的MTU 1500 - 20 = 1480字节。
在首部的固定部分的后面是一些可选字段,其长度是可变的。可选选项最大字节为40Byte。
把 IP 数据包直接放进以太网数据包的“数据”部分,因此完全不用修改以太网的规格。
IP数据包的 “标头” 部分的长度为 20 到60 字节,整个数据包的总长度最大为65,535字节。因此,理论上,一个 IP 数据包的“数据”部分,最长为 65,515字节。前面说过,以太网数据包的“数据”部分,最长只有 1500 字节。因此,如果 IP 数据包超过了 1500 字节,它就需要分割成几个以太网数据包,分开发送了。
每个字段的含义如下:
- 版本(version)
占 4 位,表示 IP 协议的版本。通信双方使用的 IP 协议版本必须一致。目前广泛使用的IP协议版本号为 4,即 IPv4。 - 首部长度(网际报头长度IHL)
占 4 位,可表示的最大十进制数值是 15。这个字段所表示数的单位是 32 位字长(1 个 32 位字长是 4 字节)。因此,当 IP 的首部长度为 1111 时(即十进制的 15),首部长度就达到 60 字节。当 IP 分组的首部长度不是 4 字节的整数倍时,必须利用最后的填充字段加以填充。
数据部分永远在 4 字节的整数倍开始,这样在实现 IP 协议时较为方便。首部长度限制为 60 字节的缺点是,长度有时可能不够用,之所以限制长度为 60 字节,是希望用户尽量减少开销。最常用的首部长度就是 20 字节(即首部长度为 0101),这时不使用任何选项。 - 区分服务(tos)
也被称为服务类型,占 8 位,用来获得更好的服务。这个字段在旧标准中叫做服务类型,但实际上一直没有被使用过。1998 年 IETF 把这个字段改名为区分服务(Differentiated Services,DS)。只有在使用区分服务时,这个字段才起作用。 - 总长度(totlen)
首部和数据之和,单位为字节。总长度字段为 16 位,因此数据报的最大长度为 2^16-1=65535 字节。 - 标识(identification)
用来标识数据报,占 16 位。IP 协议在存储器中维持一个计数器。每产生一个数据报,计数器就加 1,并将此值赋给标识字段。当数据报的长度超过网络的 MTU,而必须分片时,这个标识字段的值就被复制到所有的数据报的标识字段中。具有相同的标识字段值的分片报文会被重组成原来的数据报。 - 标志(flag)
占 3 位。第一位未使用,其值为 0。第二位称为 DF(不分片),表示是否允许分片。取值为 0 时,表示允许分片;取值为 1 时,表示不允许分片。第三位称为 MF(更多分片),表示是否还有分片正在传输,设置为 0 时,表示没有更多分片需要发送,或数据报没有分片。 - 片偏移(offsetfrag)
占 13 位。当报文被分片后,该字段标记该分片在原报文中的相对位置。片偏移以 8 个字节为偏移单位。所以,除了最后一个分片,其他分片的偏移值都是 8 字节(64 位)的整数倍。 - 生存时间(TTL)
表示数据报在网络中的寿命,占 8 位。该字段由发出数据报的源主机设置。其目的是防止无法交付的数据报无限制地在网络中传输,从而消耗网络资源。
路由器在转发数据报之前,先把 TTL 值减 1。若 TTL 值减少到 0,则丢弃这个数据报,不再转发。因此,TTL 指明数据报在网络中最多可经过多少个路由器。TTL 的最大数值为 255。若把 TTL 的初始值设为 1,则表示这个数据报只能在本局域网中传送。 - 协议
表示该数据报文所携带的数据所使用的协议类型,占 8 位。该字段可以方便目的主机的 IP 层知道按照什么协议来处理数据部分。不同的协议有专门不同的协议号。
例如,TCP 的协议号为 6,UDP 的协议号为 17,ICMP 的协议号为 1。 - 首部检验和(checksum)
用于校验数据报的首部,占 16 位。数据报每经过一个路由器,首部的字段都可能发生变化(如TTL),所以需要重新校验。而数据部分不发生变化,所以不用重新生成校验值。 - 源地址
表示数据报的源 IP 地址,占 32 位。 - 目的地址
表示数据报的目的 IP 地址,占 32 位。该字段用于校验发送是否正确。 - 可选字段
该字段用于一些可选的报头设置,主要用于测试、调试和安全的目的。这些选项包括严格源路由(数据报必须经过指定的路由)、网际时间戳(经过每个路由器时的时间戳记录)和安全限制。 - 填充
由于可选字段中的长度不是固定的,使用若干个 0 填充该字段,可以保证整个报头的长度是 32 位的整数倍。 - 数据部分
表示传输层的数据,如保存 TCP、UDP、ICMP 或 IGMP 的数据。数据部分的长度不固定。
传输层(TCP包)
依靠IP协议提供的报文分割和重组机制,TCP包头中就没有“包长度”字段,而完全依靠IP层去处理分帧。这就是为什么TCP常常被称作一种“流协议”的原因,开发者在使用TCP服务的时候,不必去关心数据包的大小,只需将SOCKET看作一条数据流的入口,往里面放数据就是了,TCP协议本身会进行拥塞/流量控制。
- 源端口
第一个字段是 源端口( source port ),它的长度为 16 位,表示报文 发送方 的端口号。 - 目的端口
第二个字段是 目的端口( destination port ),它的长度为 16 位,表示报文 接收方 的端口号。 - 序号
序号( sequence number )字段,长度为 32 位,表示数据首字节的序号。在三次握手阶段,SYN 指令也是通过该字段,将本端选定的 起始序号 告诉接收方。 - 确认号
确认号 ( acknowledgement number )字段,长度为 32 位。它表示已确认收到的数据序号,它的值为:已收到数据最后一个字节的序号加一,即接收方期望进一步接收的数据序号。 - 头部长度
头部长度 ( header length )字段,长度为 4 位,表示 TCP 报文头部的长度,也可称为 数据偏移 ( data offset )。跟 IP 协议一样,TCP 头部长度字段也不是以字节为单位,而是以 32 位字(4字节)为单位。 - 保留
保留 ( reversed )字段,长度为 3 位,保留未用。 - 标志位
标志位( flags ),长度为 9 位,用于保存一些标志位。前面提到的 SYN ACK FIN 等指令,就是以标志位的形式保存在该字段中。这样的标志位,总共有 9 个:
NS ,ECN显式拥塞通知,属于 TCP 扩展,略;
CWR ,同样属于 TCP 扩展,略;
ECE ,同样属于 TCP 扩展,略;
URG ,紧急数据指令,表示紧急指针有效,报文段包含高优先级数据;
ACK ,确认指令,表示确认号有效,对已接收数据进行确认;
PSH ,立即推送指令,指示接收方立即将数据提交给应用层,不用等缓冲区装满;
RST ,重置指令,表示出现严重错误,常用于拒绝非法报文段以及拒绝连接请求;
SYN ,序号同步指令,在 TCP 三次握手建立连接时,将本端选定序号告诉对端;
FIN ,连接关闭指令,用于告诉对端,本端数据已发送完毕,连接关闭;
窗口大小
窗口大小( window size )字段长度为 16 位,表示当前报文发送者接收窗口的大小,单位一般是 字节 。接收窗口表示接收方还能接收的数据大小,用于实现 TCP 流量控制 机制,后续章节再展开介绍。 - 校验和
校验和( checksum )字段长度为 16 位,保存报文段的校验和,用于纠错。跟 UDP 协议一样,TCP 整个报文段都会参与校验和计算。除此之外,TCP 还会在报文段前面拼接一个 IP 伪头部,同时参与校验和计算。
- 紧急指针
紧急指针( urgent pointer )字段长度为 16 位,仅在 URG 标志位开启时有效,它的值为紧急数据末字节,相对于当前报文段数据序号的偏移量。这意味着,该偏移量与序号字段相加即可得到紧急数据最后一个字节的序号。
URG 标志位和紧急指针一起为 TCP 提供了 紧急模式 ( urgent mode ),以便在正常数据流中传输紧急数据。在套接字编程中,紧急数据经常被称为 带外数据 ( out-of-band data )。 - 选项
选项( options )字段包含一些可选记录,总长度最多可达 40 字节。各个选项记录依次排列,每个选项最开始是 1 字节长的 类型( kind )字段,说明选项的类型。
应用层
理论上讲以上三层协议已经可以完全支持数据从一台主机传输到另一台主机。 但是考虑到数据传输的安全性,数据流粘包拆包相关,数据格式规范化等等问题,在应用层定义了各种各样的协议来规范数据传输的标准和基础的校验,常见的有 http、FTP、SMTP 等,通过这些规范化协议约定数据传输双方的行为。
数据传输
数据包
包、帧、数据包、段、消息
以上五个术语都用来表述数据的单位,大致区分如下:
- 包:可以说是全能性术语;
- 帧:用于表示数据链路层中包的单位;
- 数据包:是 IP 和 UDP 等网络层以上的分层中包的单位;
- 段:则表示 TCP 数据流中的信息;
- 消息:是指应用协议中数据的单位。
每个分层中,都会对所发送的数据附加一个首部,在这个首部中包含了该层必要的信息,如发送的目标地址以及协议相关信息。通常,为协议提供的信息为包首部,所要发送的内容为数据。在下一层的角度看,从上一层收到的包全部都被认为是本层的数据。
数据处理流程
以用户 a 向用户 b 发送邮件为例子:
① 应用程序处理
首先应用程序会进行编码处理,这些编码相当于 OSI 的表示层功能;
编码转化后,邮件不一定马上被发送出去,这种何时建立通信连接何时发送数据的管理功能,相当于 OSI 的会话层功能。
② TCP 模块的处理
TCP 根据应用的指示,负责建立连接、发送数据以及断开连接。TCP 提供将应用层发来的数据顺利发送至对端的可靠传输。为了实现这一功能,需要在应用层数据的前端附加一个 TCP 首部。
③ IP 模块的处理
IP 将 TCP 传过来的 TCP 首部和 TCP 数据合起来当做自己的数据,并在 TCP 首部的前端加上自己的 IP 首部。IP 包生成后,参考路由控制表决定接受此 IP 包的路由或主机。
④ 网络接口(以太网驱动)的处理
从 IP 传过来的 IP 包对于以太网来说就是数据。给这些数据附加上以太网首部并进行发送处理,生成的以太网数据包将通过物理层传输给接收端。
⑤ 网络接口(以太网驱动)的处理
主机收到以太网包后,首先从以太网包首部找到 MAC 地址判断是否为发送给自己的包,若不是则丢弃数据。
如果是发送给自己的包,则从以太网包首部中的类型确定数据类型,再传给相应的模块,如 IP、ARP 等。这里的例子则是 IP 。
⑥ IP 模块的处理
IP 模块接收到 数据后也做类似的处理。从包首部中判断此 IP 地址是否与自己的 IP 地址匹配,如果匹配则根据首部的协议类型将数据发送给对应的模块,如 TCP、UDP。这里的例子则是 TCP。
另外吗,对于有路由器的情况,接收端地址往往不是自己的地址,此时,需要借助路由控制表,在调查应该送往的主机或路由器之后再进行转发数据。
⑦ TCP 模块的处理
在 TCP 模块中,首先会计算一下校验和,判断数据是否被破坏。然后检查是否在按照序号接收数据。最后检查端口号,确定具体的应用程序。数据被完整地接收以后,会传给由端口号识别的应用程序。
⑧ 应用程序的处理
接收端应用程序会直接接收发送端发送的数据。通过解析数据,展示相应的内容。
TCP 连接/断开
三次握手
TCP 提供面向有连接的通信传输。面向有连接是指在数据通信开始之前先做好两端之间的准备工作。
所谓三次握手是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发。
第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端确认。
第二次握手:服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。
第三次握手:客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
四次挥手
四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发。
由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。
中断连接端可以是客户端,也可以是服务器端。
第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。
第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。
如果第2次挥手的ack和第3次挥手的fin之间如果没有数据需要传输的话,是可以合并为一个包(fin+ack)来传输的,也就是压缩成三次挥手
抓包分析
抓包工具
这里使用的Wireshark
。
下面列出一些过滤规则:
-
协议过滤
直接在Filter框中直接输入协议名即可。注意:协议名称需要输入小写。
tcp,只显示TCP协议的数据包列表
http,只查看HTTP协议的数据包列表
icmp,只显示ICMP协议的数据包列表 -
ip过滤
ip.src ==192.168.1.104 显示源地址为192.168.1.104的数据包列表
ip.dst ==192.168.1.104, 显示目标地址为192.168.1.104的数据包列表
ip.addr == 192.168.1.104 显示源IP地址或目标IP地址为192.168.1.104的数据包列表 -
端口过滤
tcp.port == 80, 显示源主机或者目的主机端口为80的数据包列表。
tcp.srcport == 80, 只显示TCP协议的源主机端口为80的数据包列表。
tcp.dstport == 80,只显示TCP协议的目的主机端口为80的数据包列表。 -
Http模式过滤
http.request.method==“GET”, 只显示HTTP GET方法的。
在本次抓包中过滤规则如下:
ip.addr == 103.46.128.44 && tcp.port == 47424
含义为:显示源IP地址或目标IP地址为103.46.128.44
并且源主机或者目的主机端口为47424
的数据包。
在这里服务器的IP为103.46.128.44
端口号为47424
,
客户端的IP为172.16.2.102
端口号每次重新进行socket连接时会进行改变。
握手抓包
第一次握手
第二次握手
第三次握手
数据抓包
发送数据1234567890
应答
挥手抓包
第一次挥手
第二次和第三次挥手合并
第四次挥手