计算机网络基础3--TCP/IP协议栈

TCP/IP协议栈 Transmission Control Protool/Internet Protocol

TCP/IP是一个Protocol Stack,包括TCP、IP、UDP、ICMP、RIP、TELNET、FTP、SMTP、ARP等许多协议;协议栈分为四层:从上到下应用层、传输层、Internet层(又称网际层)、网络访问层(又称网络接口层)。

  • 应用层 – 对应OSI七层模型的应用层、表示层、会话层
  • 传输层 – 对应OSI七层模型的传输层
  • Internet层(又称网际层) – 对应OSI七层模型的网络层
  • 网络访问层(又称网络接口层) – 对应OSI七层模型的数据链路层、物理层

3.1 应用层协议

应用层传输的消息称为Message,TCP/IP的应用层协议如下:
TCP/IP的应用层协议


3.2 传输层协议 – TCP/UDP

传输层协议分为TCP和UDP。PDU通过传输层加入首部后被封装为数据段segment。

  • TCP是面向连接的协议,传输前必须建立虚拟链路,结束后拆除链路,传输可靠的数据流,比如发送邮件、传输文件用的都是TCP协议,但是效率不如UDP;
  • UDP,User Datagram Protocol,无连接的协议,相对TCP不可靠,视频、语音聊天使用UDP协议。
    TCP_UDP协议对比

3.2.1 TCP协议

  1. TCP协议特性
    • 工作在传输层
    • 面向连接协议
    • 全双工协议
    • 半关闭
    • 错误检查
    • 将数据打包成段,排序
    • 确认机制
    • 数据恢复,重传
    • 流量控制,滑动窗口
    • 拥塞控制,慢启动和拥塞避免算法

  1. TCP协议报文段包头字段总结
    TCP包头
  • 源端口、目标端口:源端口、目标端口分别占用16位。Internet网络进程与进程之间通信,通过端口来进行区分,一个计算机端口某个时刻只能被一个进程占用,通过指定源端口和目标端口,就可以知道是哪两个进程需要通信。

TCP最多2^16个端口号,范围为0-65535;源端口号为本机客户端,随机分配的;目标端口号为服务端,每个应用层程序都要约定固定的端口。
对于服务端的端口号,0-1023只能是系统管理员账户使用,普通用户只能用1024及之后的。客户端随机端口号范围:49152-65535
单次抓包结构示意图

  • 序号,Sequence Number:占用32位。表示本报文段所发送数据部分的第一个字节的编号。在TCP协议中,传送的是有序的字节流,每一个字节都会被编号,每个字节的编号称为字节序列号,包头中的序号是报文段数据部分的第一个字节的序列号,作为本报文段的编号。由于序列号由32位表示,所以每2^32个字节,就会出现序列号回绕,再次从0开始
  • 确认号,Ack Number:占用32位。表示接收方期望收到发送方下一个报文段segment数据部分的第一个字节的编号。也就是告诉发送发:我希望你(指发送方)下次发送的数据的第一个字节数据的编号是这个确认号。

确认号 = 接收报文段的序号 + 数据长度,即确认号指定了下一个报文段的数据部分的第一个字节序号
假如A和B通信,A发送"hello\n"给B,报文段位序号为2379453244,因为当前报文段数据长度为6字节,则接收方收到该报文段后,接收方应答发送方的报文段中的确认号为2379453250,表示确认已经收到前面的6字节数据,请发送下一个报文段。
而B的应答报文中的序号,代表应答字节流的第一个字节序号,逻辑与A发送信息给B是一样的,即:A下一次发生报文段的确认号 = B的应答报文序号 + 应答报文数据部分长度
这样A-B通信通过确认号,确认对方收到信息后,再给对方发送消息,形成闭环可靠的数据流。

**初始序号,ISN(Initial Sequence Number):** 当新连接建立的时候,第一个字节数据的序号称为ISN(Initial Sequence Number),即初始序号。
ISN一开始并不一定就是1。在**RFC(规定网络协议的文档)**中规定,ISN的分配是根据时间来的。当操作系统初始化的时候,有一个全局变量假设为`g_number`被初始化为1(或0),然后每隔4us加1. 
当`g_number`达到最大值的时候又绕回到0.当新连接建立时,就把`g_number`的值赋值给ISN.

两次报文传输抓包试验分析:293号报文的ack表示已经收到292号报文的116个字节。
292报文:
seq:19192 len:116
292报文

293报文:
ack:19208 = 1912 +116
293报文


  • 数据偏移:⽤于表⽰TCP所传输的数据部分应该从报文的哪一位开始计算。可见TCP首部长度不是固定的。

数据偏移占4位二进制,最大偏移量15,每一个偏移量代表4字节。所以TCP首部 最大15 * 4 = 60 字节

  • URG:表示本报文段中发送的数据是否包含紧急数据。后面的紧急指针字段(urgent pointer)只有当URG=1时才有效

  • ACK:表示是否前面的确认号字段是否有效。ACK=1,表示有效。只有当ACK=1时,前面的确认号字段才有效。TCP规定,连接建立后,ACK必须为1,带ACK标志的TCP报文段称为确认报文段

  • PSH:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间。如果为1,则表示对方应当立即把数据提交给上层应用,而不是缓存起来,如果应用程序不将接收到的数据读走,就会一直停留在TCP接收缓冲区中

  • RST:如果收到一个RST=1的报文,说明与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。或者说明上次发送给主机的数据有问题,主机拒绝响应,带RST标志的TCP报文段称为复位报文段

  • SYN:在建立连接时使用,用来同步序号当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当SYN=1,ACK=1时,表示对方同意建立连接。SYN=1,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中SYN才置为1,带SYN标志的TCP报文段称为同步报文段

  • FIN:表示通知对方本端要关闭连接了,标记数据是否发送完毕。如果FIN=1,即告诉对方:“我的数据已经发送完毕,你可以释放连接了”,带FIN标志的TCP报文段称为结束报文段

  • 窗口大小, Window Size:表示现在允许对方发送的数据量,也就是告诉对方,从本报文段的确认号开始允许对方发送的数据量/一次发多少个包

累积确认:真正的TCP传输的时候不是说发一个包对方回应一个包,再发一个再回应一个,这样效率很低,通常做法法是一次发多个包,对方确认最后一个包就行了。

滑动窗口:Window Size=Num就是固定窗口,固定速率,这种不太现实。滑动窗口原理如图所示,其逻辑是,发送端先尝试一次发3个包,接收只接收了2两个,并在应答中告诉对方,我当前网络环境只能一次收2个包,即确认号Ack 3(告诉发送方下一次发送的数据的序号的同时,变相告诉发送方一次只能接收2个包);真正通信中更多的就是采用滑动窗口,根据实时情况调整发送速率。

TCP滑动窗口

  • 校验和:提供额外的可靠性
  • 紧急指针:urgent pointer,标记紧急数据在数据字段中的位置,只有当URG=1时才有效
  • 选项部分:其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,选项部分最长为:(2^4-1)*4-20=40字节

常见选项:
最大报文段长度:Maxium Segment Size,MSS。指明自己期望对方发送TCP报文段时那个数据字段的长度。默认是536字节。数据字段的长度加上TCP首部的长度才等于整个TCP报文段的长度。MSS不宜设的太大也不宜设的太小。若选择太小,极端情况下,TCP报文段只含有1字节数据,在IP层传输的数据报的开销至少有40字节(包括TCP报文段的首部和IP数据报的首部)。这样,网络的利用率就不会超过1/41。若TCP报文段非常长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片装配成原来的TCP报文段。当传输出错时还要进行重传,这些也都会使开销增大。因此MSS应尽可能大,只要在IP层传输时不需要再分片就行。在连接建立过程中,双方都把自己能够支持的MSS写入这一字段。 MSS只出现在SYN报文中。即:MSS出现在SYN=1的报文段中
窗口扩大:Windows Scaling。为了扩大窗口,由于TCP首部的窗口大小字段长度是16位,所以其表示的最大数是65535。但是随着时延和带宽比较大的通信产生(如卫星通信),需要更大的窗口来满足性能和吞吐率,所以产生了这个窗口扩大选项
时间戳: Timestamps。可以用来计算RTT(往返时间),发送方发送TCP报文时,把当前的时间值放入时间戳字段,接收方收到后发送确认报文时,把这个时间戳字段的值复制到确认报文中,当发送方收到确认报文后即可计算出RTT。也可以用来防止回绕序号PAWS,也可以说可以用来区分相同序列号的不同报文。因为序列号用32为表示,每2^32个序列号就会产生回绕,那么使用时间戳字段就很容易区分相同序列号的不同报文

TCP失序字节处理及理解?
假设主机A通过一条TCP连接向主机B上的一个进程发送数据,假定数据流由一个包含500000字节的文件组成,其MSS(最大报文段长度)为1000字节,数据流的首字节编号是0,如下图所示。该TCP将为该数据流构建500个报文段,给第一个报文段分配序号0,第二个报文段分配序号1000,以此类推,每一个序号被填入到相应TCP报文段首部的序号字段中。
数据流分段

假设主机A已收到主机B的包含字节0-535字节的报文段,以及另一个包含字节900-1000的报文段。由于某种原因,主机A还没有收到字节536-899的报文段。在这个例子里,主机A为了重新构建主机B的数据流,仍在等待字节536(和其后的字节)。因此,A到B的下一个报文段将在确认号字段中包含536。因为TCP只确认该流中到第一个丢失字节为止的字节,所以TCP提供的是累积确认
主机A虽然收到了字节900-1000的报文段,但是并不会在下一个发往主机B的报文段的确认号字段中填1001,因为535后面的字节还没有得到确认,而收到的900-1000字节的报文段属于失序到达,对于失序到达的报文段的处理方法由TCP编程人员去具体实现,有两个基本选择:一是丢弃失序报文段,二是保留失序字节并等待缺少的字节以填补该间隔(这是实践中采用的方法)


3.2.3 TCP三次握手和四次挥手

TCP三次握手

  • 第一次握手,请求端主动打开,请求建立连接,设置SYN=1,和初始序号seq=ISN1,由closed状态转换为SYN-SENT;
  • 第二次握手,接收端被动收到A发来的请求,由closed状态转换为LISTEN状态,此时接收端也是第一次建立连接,所以置SYN=1,同时要应答请求端,置ACK=1,同时置序号和确认号seq=ISN2,ack=ISN1+1,状态再由LISTEN转换为SYN-RCVD;
  • 第三次握手,请求端收到接收端的应答,发送建连报文,ACK=1,seq=ISN1+1,ack=ISN2+1。
  • 三次握手完成,1、确定了初始序号和确认号,2、建立了连接,3、请求端和客户端都进入了ESTABLISHED状态。
    TCP四次挥手
    四次挥手即可以是客户端也可以是服务端。二者初始状态都为ESTABLISHED,以客户端为例:
  • 第一次挥手,客户端请求端口,置FIN=1,seq=x,客户端由ESTABLISHED转换为FIN-WAIT-1;
  • 第二次挥手,服务端收到断开请求,服务端可能还在给客户端传输数据,所以先应答一下,不会立即同意断开,ACK=1,seq=y,ack=x+1,服务端状态切换为CLOSE-WAIT,客户端收到应答,状态进入FIN-WAIT-2;
  • 第三次挥手,数据传完后,服务端置FIN=1,ACK=1,seq=y,ack=x+1,状态进入LAST-ACK;
  • 第四次挥手,客户端收到服务端第二次应答后,再次发生一个断开数据包,ACK=1,seq=x+1,ack=y+1,客户端进入TIME-WAIT状态,最长等待2MSL。MSL:最长传输时间

为什么进入TIME-WAIT,原因是确认没有残留的未传输完成数据。
孤儿连接: 第二次挥手后,迟迟不发第三次挥手(比如突然对方网络断开了),这个时候发起断开的请求方就进入了孤儿连接状态。这种废进程状态会消耗计算机资源。
Linux防止孤儿连接长时间停留在内核中,指定了最大孤儿连接数目和孤儿连接生存时间:
/proc/sys/net/ipv4/tcp_max_orphans
/proc/sys/net/ipv4/tcp_fin_timeout

TCP三次握手和四层挥手抓包试验:
TCP三次握手和四层挥手抓包试验

时序图,序号和确认号为抓包试验中的后三位:
对应时序图

三次握手和四层握手涉及发送方和接收方的状态,这些状态的专业名词叫有限状态机FSM:Finite State Machine:

  • CLOSED 没有任何连接状态
  • LISTEN 侦听状态,等待来自远方TCP端口的连接请求
  • SYN-SENT 在发送连接请求后,等待对方确认
  • SYN-RECEIVED 在收到和发送一个连接请求后,等待对方确认
  • ESTABLISHED 代表传输连接建立,双方进入数据传送状态
  • FIN-WAIT-1 主动关闭,主机已发送关闭连接请求,等待对方确认
  • FIN-WAIT-2 主动关闭,主机已收到对方关闭传输连接确认,等待对方发送关闭传输连接请求
  • TIME-WAIT 完成双向传输连接关闭,等待所有分组消失
  • CLOSE-WAIT 被动关闭,收到对方发来的关闭连接请求,并已确认
  • LAST-ACK 被动关闭,等待最后一个关闭传输连接确认,并等待所有分组消失
  • CLOSING 双方同时尝试关闭传输连接,等待对方确认 – 客户端和服务端同时发生断开连接时的状态

有限状态机FSM:Finite State Machine:
客户端先发送一个FIN给服务端,自己进入了FIN_WAIT_1状态,这时等待接收服务端的报文,该报文会有三种可能:

只有服务端的ACK
只有服务端的FIN
基于服务端的ACK,又有FIN

  1. 只收到服务器的ACK,客户端会进入FIN_WAIT_2状态,后续当收到服务端的FIN时,回应发送一个ACK,会进入到TIME_WAIT状态,这个状态会持续2MSL(TCP报文段在网络中的最大生存时间, RFC 1122标准的建议值是2min).客户端等待2MSL,是为了当最后一个ACK丢失时,可以再发送一次。因为服务端在等待超时后会再发送一个FIN给客户端,进而客户端知道ACK已丢失
  2. 只有服务端的FIN时,回应一个ACK给服务端,进入CLOSING状态,然后接收到服务端的ACK时,进入TIME_WAIT状态
  3. 同时收到服务端的ACK和FIN,直接进入TIME_WAIT状态

客户机端的三次握手和四次挥手状态转换
服务器端的三次握手和四次挥手状态转换


3.2.4 TCP协议Port

TCP为上层协议提供服务,通过端口号来确认上层服务的应用协议(比如上一层的应用程序端口号为80,则这个程序为http协议),TCP/UDP协议各自的端口范围均为0-65535

  • 0-1023,系统端口或特权端口(仅管理员可用),永久的分配给固定的系统应用使用,22/tcp(ssh), 80/tcp(http), 443/tcp(https)
  • 1024-49151:用户端口或注册端口,但要求并不严格,分配给程序注册为某应用使用,1433/tcp(SqlServer),1521/tcp(oracle), 3306/tcp(mysql),11211/tcp/udp (memcached)
  • 49152-65535:动态端口或私有端口,客户端程序随机使用的端口,其范围的定义文件:/proc/sys/net/ipv4/ip_local_port_range

TCP为上层协议提供服务,对应常见的应用层协议端口号:

22 – ssh
80 – http
21 – ftp
23 – telnet
53 – DNS
3306 – mysql
11211 – memcached

UDP为上层协议提供服务,对应常见的上层协议端口号:

53 – DNS(TCP/UDP协议,对应上层DNS服务,端口号都为53)
69 – TFTP
161 – SNMP
11211 – memcached (TCP/UDP协议,对应上层memcached服务,端口号都为11211)

TCP/UDP端口映射

linux查看本机应用程序使用了哪些端口号:cat /etc/services |grep PortNum
linux查看真的客户端随机端口号范围(所以是可以修改的):cat /proc/sys/net/ipv4/ip_local_port_range
IANA:互联网数字分配机构(负责域名,数字资源,协议分配)

3.2.5 TCP超时重传

异常网络状态下(丢包),TCP服务必须能够重传超时时间内未收到确认的TCP报文段。TCP模块为每个TCP报文段都维护了一个重传定时器,
该定时器在TCP报文段第一个被发送时启动;如果超时时间内未收到接收方的应答,TCP模块将重传TCP报文并重置定时器。
TCP超时重传相关的内核参数:

/proc/sys/net/ipv4/tcp_retries1,指定底层IP接管之前,TCP最少执行的重传次数。默认为3次;
/proc/sys/net/ipv4/tcp_retries2,指定放弃连接前,TCP最多可以执行的重传次数,默认15次;

TCP还有拥塞控制策略,参考标准文档RCF581

3.2.6 UDP协议

局域网应该还可以,传输性能好,有限的错误检测功能。绝大部分互联网应用都用TCP。

  • 工作在传输层
  • 提供不可靠的网络访问
  • 非面向连接协议
  • 有限的错误检查
  • 传输性能高
  • 无数据恢复特性
    UDP包头

3.3 网络层协议 Internet Protocol

网络层协议

3.3.1 ICMP协议

ICMP协议,Internet Control Messages Protocol,因特网信报控制协议。作用:测试网络是否通畅

  • PING ip,发送的数据包就是基于ICMP协议的数据包。ICMP协议数据包就是用来测试网络的连通性,根据返回网络状态码判断网络状态
  • linux可以通过修改/proc/sys/net/ipv4/icmp_echo_ignore_all配置项,临时关闭ICMP:echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all,这样其他服务器ping这台服务器,避免黑客攻击
  • 基于ICMP的网络攻击:ping -f -s 65507 IP-f让CPU尽其所能的去ping指定的IP;-s,修改ping时SMTP的数据包的大小,最大65507字节;通过这条命令很简单的实现网络攻击,使对方网络瘫痪。企业为了网络安全,会设置防火墙把ICMP协议禁用。

ICMP协议还可以发广播ping -b 广播地址IP,比如ping -b 192.168.8.255,作用:检查广播域中哪些主机网络是通的,哪些有问题

  • 默认都是关了的,linux广播临时配置开启:echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

3.3.2 ARP协议

1 作用:ARP协议,Address Resolution Protocol,地址解析协议。通过ARP协议,利用IP地址,查找到对应的Mac地址

  • ARP协议具有缓存机制,会将解析到的IP和Mac地址映射表临时缓存到主机中,大概10min;
  • 查看本机的arp缓存表: linux:arp -n; windows:arp -a

ARP路由表

为什么计算机配了IP及路由后,两个机器之间就可以通信了呢?

1 网络通信的时候,主机接收到的数据包首先到达物理层,然后再往数据链路层传;
2 在数据链路层首先分析数据包中的目标Mac地址是不是本机的MAC地址,如果是才接收并继续往网络层传输,不是直接抛弃;
3 而发送端发送数据的时候,开始只知道目的IP,是根据目的IP发送数据包的,并不知道目的Mac地址,数据链路层的包头怎么填目的MAC地址呢?如果不填发送的数据包将会被抛弃无法被目的主机接收。
事实上,就是通过ARP协议,利用IP地址,查找到对应的Mac地址,然后在数据报文里面写上Mac地址,就能收到了。

ARP协议理解

2 ARP协议查找Mac过程:

  • ARP协议第一次通信通过发送广播查找目标主机:假设主机A(ip1)给主机B(ip2)通信,主机A先发广播问谁是ip2,所有收到消息的主机中,B发现它就是,于是把自己的Mac地址回给A;
  • A收到B的确认消息后,将B的IP和Mac地址缓存到自己的ARP映射表中。下次A-B通信的时候,就通过缓存表直接通信了。

如果A-B隔着路由怎么办呢?
ARP协议通信的时候,会先计算目标IP在不在同一个网络里,如果不在同一个网络,就不会通过ARP广播直接查找目标主机
。假设主机A(Mac_A)和主机C(Mac_C)通信,隔着路由器:

  • A先向路由器网关发送广播请求,(机器A提前配了网关信息的,所以A知道路由器网关IP1及其Mac1,那么数据帧中的请求可以理解为网关IP1-Mac1,请求发生广播,目标Mac是Mac_C);
  • 然后路由器再按ARP广播的方式查找下一个网络中谁是Mac_C。如果有多个路由器,以此类推,直到找到Mac_C为止。
  • 发送的数据帧里,数据帧的首部就会添加多个目标Mac 源Mac;假设主机A、主机C中间只隔了一个路由B,A与路由B的1口连,C与路由B的2口连,则数据帧的大致结构如下图所示(注意IP不会包含路由器的IP):

ARP通信过程示意图
所以,ARP协议通信过程是一段一段寻找一段一段通信,在整个广播域中直到找到目的地址。

3 ARP协议应用场景理解

  • 计算机启动的时候,就会通过ARP协议发一次广播,检查网络中有没有和本机IP冲突的主机。下图中的Gratuitous ARP,翻译过来叫免费ARP。
  • 启动后,arp映射表是空的,因为没有跟任何主机通信过。这个时候如果去ping一个IP(ICMP协议),首先就会通过ARP协议,发送广播去网络中找谁是这个IP。找到后,ICMP协议,才能在它的数据包中填写目标Mac地址。
  • TCP请求,不知道目标IP的Mac时,都会通过ARP,先找到目标IP的Mac。
  • ARP还可以检查网络中是否有网络冲突arping -i eth0 +ip,可以通过指定端口,查找网络中指定的ip对应有几个Mac,如果有多个Mac地址,说明IP冲突了。
  • 反向ARP:反向ARP就是通过Mac查找IP。网吧常用这种协议。

ARP应用场景示例


3.3.3 综合TCP、IP、ARP理解一次完整的网络请求过程

场景网络中,应用程序A:192.168.1.5和应用程序B:192.168.1.6要建立连接进行通信,描述请求建立连接的过程?

  • 首先应用程序A发起请求,问传输层我可以和1.6进行可靠的通信吗?
  • 传输层收到请求,ok,我用TCP协议。
  • 于是,应用层把第一次握手的请求Message发送给传输层,并通知传输层把这个信息传给1.6;
  • 传输层(TCP协议)收到Message后,将Message封装成Segment(包含源端口、目标端口,序号、确认号,SYN等),直接把数据传给Internet层,并通知Internet层把这个信息传给1.6;
  • Internet层(IP、ARP)收到请求后将分组封装成数据包package(包含源IP、目标IP),传给网络访问层,数据链路层问ARP,你的映射里中1.6的Mac地址吗;ARP一看没有,于是通过ARP广播,查找1.6所在主机的Mac;通过ARP广播应用程序A所在主机和应用程序B所在主机均知道了对方的Mac
  • 找到1.6的Mac后,网络访问层将数据包封装成数据帧frame(包含源Mac、目标Mac等),并最终以二进制形式传给B应用程序。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一次完整的网络请求过程

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个两个四个三

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值