简要复习TCP/IP体系结构之运输层(上篇)

一、运输层与应用层的关系:

socket抽象层:

        socket是在应用层与传输层之间交互的抽象层,它是帮助用户在应用层调用传输层功能的,它由一个记录着网络通信所需要信息的结构体和一系列最终调用到运输层功能的接口所组成。在具体应用中,以Linux系统为例,用户可以通过socket()函数来创建一个套接字文件,它存储在内存中,但这里的套接字实际上就是指上述的”记录着网络通信所需要信息的结构体”,并不包括“一系列最终调用到运输层功能的接口”(这些是固定在操作系统内核中的),而网络通信所需要的信息包括要用到的传输层协议,IP地址和端口号等,用户可以在sockaddr结构体中给出,并用bind函数,将这些信息刻录在socket函数创建的套接字文件中。 

 补充:

        首先,socket不仅是在应用层与传输层之间交互的抽象层,它也可以在应用层与网络层或数据链路层之间交互,这取决于套接字的类型和协议 。例如,原始套接字可以让应用层直接访问IP层或数据链路层的功能 。

        其次,socket函数创建的套接字文件不仅包含了网络通信所需要的信息,还包含了一些其他的属性,如套接字状态、选项、引用计数等 。这些属性可以通过getsockopt和setsockopt函数来获取和设置 。

二、 两个主要的运输层协议: 

        用户数据报协议(User Datagram Protocol)和传输控制协议(Transmission Control Protocol):

        UDP不提供可靠的传输服务,它是一种最简化的运输层协议,只做了运输协议能够做的最少的工作。

        而TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP在IP网络中提供了一种端到端的可靠数据传输服务,它通过序号、确认号、校验和、重传机制、流量控制和拥塞控制等手段来保证数据的完整性、有序性和有效性。TCP还提供了端口号来区分不同的应用程序,以及窗口大小来调节发送和接收方的数据缓冲区。

三、TCP重点概述

        有关UDP和TCP报头各个详细字段的作用,及选择确认、超时重传等细碎机制这里不做详述,有需要可查阅《计算机网络自顶向下方法》第3章。

(1)序号和确认号

        TCP中序号和确认号描述的是以字节为单位的正在发送和已收到的数据。

        序号seq是指本端发送的TCP报文段中数据载荷的第一个字节的序号,如果A端与B端通信,A端起始序号为0,一共要传输1000字节数据,本次传输的报文段的序号为100,数据载荷共300字节,则代表已经传送了0~99字节的数据,正在传送的报文的数据载荷的起始是第100字节数据。

        确认号ack是指本端要接收的数据的起始序号,接上述例子,B端收到来自A端的报文后,通关计算可以得出已经收到了0~99号字节的数据+该报文段中传输的100~399号字节的数据,那么接下来B端需要接收A端的第400号字节及之后字节的数据,所以B端向A端发送的报文端中确认好应为400。

         需要注意的是,由于滑动窗口的存在,TCP两端的通信并不是线性的,多个报文可以在连接中被同时发送,此时如果对端收到的数据并不是紧接着已收到数据之后的数据,而是更之后的数据,即序号与上一次我端发送的报文的ack不相符,此时不能对这段数据作确认,需等待收到空缺数据后,只能继续请求空缺的数据,即确认号不变。

(2)三次握手和四次挥手

“三次握手”:

为什么是“三次握手”?

        三次握手的目的本质上是在于确保连接的双方都具备接收对端数据的能力和向对端发送数据的能力,这样建立的连接才是有效的。从这个角度来看三次握手:①客户端向服务端发送SYN报文证明客户端有向服务端发送报文的能力。②服务端接收报文后,知道了客户端有向“我”发送报文的能力,随后向客户端发送SYN+ACK报文,可以同时向客户端证明“我”拥有接收你报文的能力,并且“我”也向你发送了报文,说明“我”还有向你发送报文的能力。③最后,客户端收到服务端的报文后知晓了服务端拥有两种能力,但此时服务端还不能知道客户端有没有收到自己的报文,所以客户端必须再向服务端发送一条ACK报文,向服务端证明自己拥有接收服务端报文的能力。因此,三次握手是能验证通信两端都拥有通信能力的最少次数。

        除此之外还有一个原因,三次握手可以防止在网络中滞留的TCP请求连接报文段的不良影响,例如,客户端的第一个请求报文段在网络中滞留,导致客户端超时重传,再次向服务端请求建立TCP连接,这次连接建立成功后,顺利完成通信并通过四次挥手关闭连接;然而此时客户端第一次发送的请求报文,脱离了滞留状态,成功到达服务端,服务端会误以为这是来自客户端的又一次连接请求,向客户端发送SYN+ACK报文段,并立刻进入连接已建立状态(少了一次握手),此时客户端实际上并没有发送请求,收到服务端的报文后会将之丢弃,服务端却并不知道这个情况,会白白的浪费连接资源。

“四次挥手”:

为什么是“四次挥手”?

        按照三次握手的想法,中间的来自服务端的ACK报文+FIN报文似乎是可以合二为一的,从而变为“三次挥手”。实际上却完全不能。因为释放连接与建立连接不同,一端释放连接仅能表达“我不再向你发送数据了”,但是对端仍能向“我”发送数据。服务端收到客户端FIN请求后,会立刻向客户端发送ACK确认报文端,让客户端成功释放“客→服”的连接,但此时服务端可能还要向客户端发送一些数据,所以不能立刻断开“服→客”的连接,因此不能将服务端的ACK报文+FIN报文合二为一,因此,四次挥手是能够让两端都合理释放连接的最少次数。

        在TCP四次挥手中,如果客户端不再发送数据了,向服务端发送FIN报文后,服务端却仅发送了ACK报文给客户端,却一直不能成功送达FIN报文,及一直不断开向客户端发送数据的连接(调用close(fd)失败或FIN报文始终无法成功传达),此后会怎样?

        这种情况下,客户端会一直处于FIN_WAIT_2状态,等待服务端的FIN报文。而服务端会一直处于CLOSE_WAIT状态,等待应用程序调用close(fd)来关闭连接。这样就造成了两个问题:

        客户端和服务端都无法释放连接资源,占用了系统内存和文件描述符等资源。

        客户端和服务端都无法再建立新的连接,因为同一个IP和端口只能对应一个TCP连接。

        这种情况通常被称为半打开(half-open)或僵死(zombie)连接,是一种非常不好的网络现象。它可能是由于网络故障、程序错误、攻击行为等原因造成的。

为了解决这个问题,有以下几种方法:

        在客户端设置一个超时时间(timeout),如果在一定时间内没有收到服务端的FIN报文,就主动释放连接资源,并记录日志或者报警。

        在网络层使用防火墙或者路由器等设备来检测和清除僵死连接。

滑动窗口:

        TCP的滑动窗口是一种流量控制方法,它允许发送方在停止并等待确认前连续发送多个分组,而不必每发送一个分组就停下来等待确认,从而增加数据传输的速率提高应用的吞吐量。

TCP协议用到的滑动窗口是建立在发送缓冲区和接收缓冲区中的。

发送缓冲区内的情况:

        滑动窗口将发送缓冲区从逻辑上分为了三部分:滑动窗口左边的是已经发送并得到确认了的数据,滑动窗口内的是可以发送或已发送但还没得到确认的数据,滑动窗口右边的是暂时还不能发送的数据(因为对端接收缓存区放不下)。

接收缓冲区内的情况:

        滑动窗口也从逻辑上将接收缓冲区分为了三部分:接收缓冲区中滑动窗口左边的数据,是已经接收到并且被应用程序读取的数据。这部分数据已经从缓冲区中释放出来,不占用空间。

        接收缓冲区中滑动窗口内部的数据,是已经接收到但还没有被应用程序读取的数据或者可以接收但还未接收的数据。这部分数据占用缓冲区的空间,影响窗口的大小。如果应用程序读取了这部分数据,就会释放空间,并通知发送方更新窗口的大小。

        接收缓冲区中滑动窗口右边的数据,是未接收到并且无法接收的数据。这部分数据超出了缓冲区的容量,不能被存放。如果发送方发送了这部分数据,就会被接收方丢弃,并通知发送方减小窗口的大小。

        滑动窗口协议的基本工作流程就是由接收方通告窗口的大小,这个窗口称为接收方窗口。接收方提出的窗口则是被接收缓冲区所影响的,如果数据没有被用户进程使用那么接收方通告的窗口就会相应得到减小,发送窗口取决于接收方窗口的大小。可用窗口的大小等于接收方窗口减去发送但是没有被确认的数据包大小。

滑动窗口的实现原理:

         TCP滑动窗口的本质其实就是维护几个变量,通过这些变量将TCP处理的数据分为几类,同时在发送出一个报文、接收一个报文对这些变量做一定的处理维护。

因此发送方滑动窗口的实现可采用指针法,定义三个int变量记录窗口的三个逻辑指针即可:

接收方同理。

最后,滑动窗口采用环形队列的逻辑结构确保不会逻辑值溢出缓冲区实际大小。

(有关TCP流量控制、拥塞控制等见下篇。以上部分图片资源来自《计算机网路》微课堂—— 胡科大教书匠。)

补充:

快重传:当TCP通信的一端连续收到三个重复的确认应答后,将立刻进行重传,而不需要等待计时器超时。快重传不能取代保底的超时重传,因为对端的确认报文本身就有可能丢失。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值