免费网站软件大全,wordpress中文二次元,成品影视app开发制作,wap网站一览传输层协议TCP TCP报文格式首部长度保留位32位序列号和32位确认应答号标记ACKSYNFINRSTURGPSH 16位窗口大小16位校验和16位紧急指针选项 TCP特点可靠传输实现机制-确认应答超时重传连接管理机制三次握手四次挥手特殊情况 滑动窗口流量控制拥塞控制延迟应答捎带应答面向字节流粘… 传输层协议TCP TCP报文格式首部长度保留位32位序列号和32位确认应答号标记ACKSYNFINRSTURGPSH 16位窗口大小16位校验和16位紧急指针选项 TCP特点可靠传输实现机制-确认应答超时重传连接管理机制三次握手四次挥手特殊情况 滑动窗口流量控制拥塞控制延迟应答捎带应答面向字节流粘包问题 TCP异常情况处理进程崩溃主机关机主机掉电接收方掉电发送方掉电 TCP报文格式 此处源端口和目的端口很好理解
首部长度
首部长度指的是TCP报文头部中的一个字段,它用于指示TCP报文头部占用了多少个四字节
此处的单位是四字节,把首部长度的数字*4才是真正的报头长度 TCP报头最大长度为60字节,TCP报头的前20个字节,是固定的,使TCP报头的最短长度为20字节 需要通过首部长度,来确认报头到哪里就结束了,载荷数据是从哪里开始的
保留位
在设计TCP时,虽然此处不需要,但是先占好了位置,如果后面还需要增加其他的内容,可以使用保留位中的空间,但是现在还没有使用
32位序列号和32位确认应答号
32位序列号主机A为每个发送出去的段生成一个唯一的序列号表示该段的序号。每个数据段都有一个独立的序列号确保主机B可以将它们正确地排序并重组为原始数据流。主机A在发送数据段时会将该序列号附加在数据段的头部。
32位确认应答号主机B在确认每个正确接收的数据段时会将该段的序列号确认应答号放在确认段的头部中。这样主机A就可以根据确认应答号了解哪些数据段已经正确到达目标主机。
标记
ACK
ACKAcknowledgement是TCP协议中的一个标志位用于确认接收方已经成功接收到发送方传输的数据。
在TCP协议中每当接收方成功接收并正确处理了一个TCP报文段后它会向发送方发送一个带有ACK标志位的确认报文段表示已经成功接收到数据。这个确认报文段中的ACK字段会包含一个序号表示接收方期望下一个数据报文段的序号。
通过ACK标志位发送方可以得知哪些数据已经被接收方成功接收从而可以继续发送下一个数据报文段。如果发送方在一定时间内没有收到接收方的ACK确认它会认为数据丢失触发重传机制确保数据的可靠性。
需要注意的是ACK只表示数据是否被接收方正确接收而不保证数据的正确性或顺序。TCP协议通过序号和确认机制来保证数据的可靠传输和顺序恢复。
总结起来ACKAcknowledgement是TCP协议中的一个标志位用于确认接收方已经成功接收到发送方传输的数据。通过ACK标志位发送方可以获取接收方的确认以实现数据的可靠传输和顺序恢复
SYN
SYNSynchronize是TCP协议中的一个标志位用于建立连接时进行同步和协商。
在TCP的三次握手过程中SYN标志位扮演重要的角色。具体的连接建立过程如下
客户端发送一个带有SYN标志位的TCP报文段给服务器表示客户端请求建立连接。这个报文段也包含一个初始序号ISN用于序列号的初始化。
服务器接收到客户端发送的SYN报文段后发送一个带有SYN和ACK标志位的报文段给客户端表示已经收到了请求并同意建立连接。同时服务器会选择一个初始序号作为响应的序列号。
客户端收到服务器发送的带有SYN和ACK标志位的报文段后发送一个带有ACK标志位的报文段给服务器表示确认收到了服务器的响应。这个报文段中的序号字段会设置为服务器发送的序列号加1表示客户端期望下一个数据报文段的序号。
通过这样的三次握手过程双方建立了初始的序列号并同步了连接的状态可以开始进行数据的传输。
需要注意的是SYN标志位仅在建立连接时使用而不在数据传输过程中使用。它用于同步双方的状态和序列号并确保连接的可靠性。
总结起来SYNSynchronize是TCP协议中的一个标志位用于建立连接时进行同步和协商。通过三次握手过程客户端和服务器使用SYN和ACK标志位进行状态和序列号的同步确保连接的可靠性和正确性。
FIN
2023/9/8 20:49:14
FINFinish是TCP协议中的一个标志位用于表示发送方或接收方希望关闭连接。
当一方发送了带有FIN标志位的TCP报文段时它表示该方已经完成了数据的发送并且不再发送任何数据。另一方接收到带有FIN标志位的报文段后会发送一个带有ACK标志位的确认报文段作为回应表示已经收到了关闭请求。
在完全关闭连接之前最终会有双方各发送一个带有FIN标志位的报文段以确保双方都同意关闭连接。这个过程称为四次握手Four-way Handshake。
具体的关闭过程如下: 发送方发送一个带有FIN标志位的报文段表示它已经完成了数据的发送。 接收方收到带有FIN标志位的报文段发送一个带有ACK标志位的报文段作为确认。 接收方发送一个带有FIN标志位的报文段表示它也已经完成了数据的发送。 发送方收到带有FIN标志位的报文段后发送一个带有ACK标志位的报文段作为最终的确认。 在这个过程完成后双方都认为连接已经关闭不再进行数据传输。然后操作系统会释放相关的资源结束连接。
总结起来FINFinish是TCP协议中的一个标志位用于表示发送方或接收方希望关闭连接。通过四次握手过程双方发送带有FIN和ACK标志位的报文段来协商和确认关闭连接并释放相关资源。
RST
RSTReset是TCP协议中的一个标志位用于重置连接或表示异常情况。
当一方收到一个带有RST标志位的TCP报文段时它会立即终止当前的连接并不回复任何确认。这种情况通常发生在以下几种情况下
对方端口未打开或不可达如果发送方向一个未打开或不可达的端口发送数据接收方会发送一个带有RST标志位的报文段作为响应告知发送方连接无法建立。
非法连接请求当接收方收到一个不合法或非法的连接请求时它可能会发送一个带有RST标志位的报文段来拒绝连接。
意外的连接中断在某些情况下如网络故障、硬件故障或防火墙策略等TCP连接可能会意外中断。接收方可能会发送一个带有RST标志位的报文段来终止连接并清理相关资源。
需要注意的是RST标志位表示连接的重置不同于FIN标志位用于正常关闭连接。RST标志位的使用通常表示异常情况或错误而不是正常的连接终止过程。
总结起来RSTReset是TCP协议中的一个标志位用于重置连接或表示异常情况。当接收方收到带有RST标志位的报文段时它会立即终止连接并不回复任何确认。RST标志位通常用于拒绝不合法的连接请求或表示连接的意外中断。
URG
URGUrgent Pointer是TCP协议中的一个特殊标志用于指示传输中的紧急数据。当设置了URG标志的TCP报文到达接收方时接收方会根据URG指针的值来判断报文中的哪部分数据是紧急数据并优先处理。
URG标志在TCP头部的标志字段中用于标识TCP报文的特殊属性。当设置了URG标志后TCP报文头部的URG字段中的值就会指示紧急数据的末尾位置。
传输紧急数据时通常需要与紧急指针Urgent Pointer一起使用。紧急指针是一个16位的字段它表示了紧急数据在整个TCP数据流中的偏移量。接收方根据紧急指针的值来决定从何处开始处理紧急数据。紧急指针的值是相对于序列号字段的偏移量指示了紧急数据的结束位置。
需要注意的是URG标志和紧急指针并不会自动触发紧急数据的处理而是提供了一种通知机制告知接收方有关紧急数据的信息。接收方可以根据URG标志和紧急指针的值来实现相应的处理逻辑例如及时处理紧急数据或给予其特殊的处理优先级。
总之URG标志和紧急指针是TCP协议中用于传输紧急数据的机制。它们提供了一种通知机制使发送方能够告知接收方某部分数据是紧急的并根据紧急指针的值进行相应的处理。
PSH
PSHPush是TCP协议中的一个标志位用于指示发送方应该立即将缓冲区中的数据发送给接收方而不需要等待缓冲区填满或等待定时器超时。
当设置了PSH标志的TCP报文到达接收方时接收方会告知操作系统立即将接收到的数据交给上层应用进行处理而不是等待更多的数据到达或等待缓冲区填满。这样可以确保及时将数据交付给上层应用提高实时性和响应速度。
PSH标志在TCP头部的标志字段中用于表示TCP报文的特殊属性。当设置了PSH标志位后TCP协议栈会根据该标志位来触发数据的立即发送。
PSH标志通常与应用层的数据交互相关。当上层应用发送的数据需要及时到达目的地或进行实时处理时可以设置PSH标志以便及时交付数据。
需要注意的是PSH标志仅仅是一个请求标志它只是向接收方发出请求要求接收方尽快将数据交给上层应用。接收方可以根据自身的策略和条件来决定是否立即响应该请求。
总结起来PSHPush标志是TCP协议中的一个标志位用于指示发送方应该立即将缓冲区中的数据发送给接收方而不需要等待缓冲区填满或等待定时器超时。它可以提高数据传输的实时性和响应速度。
16位窗口大小
十六位窗口大小是指TCP协议中用来控制数据流量的窗口大小字段的长度。在TCP头部中窗口大小字段占据了16个比特位16个二进制位因此被称为十六位窗口大小。
窗口大小表示接收方能够接收到的数据量在TCP连接中起到流量控制的作用。发送方根据接收方提供的窗口大小信息调整发送的数据量以确保不会导致接收方缓冲区溢出或网络拥塞。
由于十六位窗口大小字段长度有限其最大值为655352^16-1通过使用这个字段TCP连接可以控制数据的传输速度避免过多的数据积压和丢失。
需要注意的是由于十六位窗口大小的限制对于高带宽和高延迟的网络连接窗口大小可能会成为瓶颈限制了数据传输的速度。为了解决这个问题TCP引入了拥塞窗口等机制以支持更大的窗口大小和更高的传输性能。
总结起来十六位窗口大小是TCP协议中用来控制数据流量的窗口大小字段的长度占据16个比特位。窗口大小表示接收方能够接收到的数据量用于流量控制。它具有最大值为65535的限制对于高带宽和高延迟的网络连接可能会成为瓶颈。
16位校验和
23/9/8 20:53:41
16位校验和是一种用于数据完整性检验的简单校验算法。它将待发送的数据按照固定大小通常以16位为单位进行分组并计算每个分组中所有比特的和得到一个16位的校验和值。
具体计算步骤如下
将待发送的数据进行分组每组16位2个字节。 对每个分组内的所有比特进行求和忽略溢出的进位。 将求和结果取反得到最终的16位校验和。 在发送数据时发送方会将原始数据和对应的校验和一起发送给接收方。接收方在接收到数据后对接收到的每个分组进行相同的校验和计算并将计算结果与接收到的校验和进行比较。如果两者一致则说明数据在传输过程中没有发生错误如果不一致则说明数据可能发生了错误或损坏。
16位校验和是一种简单的校验算法能够检测出一部分错误如单比特错误或少量的传输错误。然而它并不能检测到所有可能的错误因此在实际应用中常常使用更复杂的校验算法如CRC循环冗余校验等以提高数据完整性的检测能力。
总结起来16位校验和是一种简单的校验算法用于检测数据的完整性。它将待发送的数据按照16位为单位进行分组计算每个分组中所有比特的和并将结果取反作为校验和。接收方在接收到数据后进行相同的计算并与发送方提供的校验和进行比较以判断数据是否发生错误或损坏。然而16位校验和仅能检测部分错误而不能覆盖所有可能的错误。
16位紧急指针
16位紧急指针是TCP协议头部中的一个字段用于指示数据流中的紧急数据的位置。紧急指针字段占据了16个比特位16个二进制位因此被称为16位紧急指针。
在TCP连接中紧急数据通常用于实时通信或某些应用层协议中需要优先处理的数据。通过设置紧急指针发送方可以向接收方传达数据流中哪些部分是紧急数据接收方可以据此优先处理这些数据。
当发送方发送具有紧急指针的数据时接收方会根据紧急指针来识别紧急数据的边界。对于紧急指针之前的数据接收方会按照正常顺序进行处理而对于紧急指针之后的数据则可能会被接收方提前处理以满足紧急数据的要求。
需要注意的是紧急指针所指示的位置是相对于当前序列号的偏移量而不是绝对位置。发送方和接收方需要按照TCP流状态保持一致以正确解读紧急指针字段。
总结起来16位紧急指针是TCP协议头部中的一个字段用于指示数据流中的紧急数据的位置。发送方可以设置紧急指针来传达紧急数据的位置接收方可以据此优先处理紧急数据。紧急指针是相对于当前序列号的偏移量需要发送方和接收方在TCP流状态中保持一致以正确解读该字段。
选项
TCP协议头部中的选项字段用于在TCP报文中传递一些可选的、与特定功能或参数相关的信息。选项字段可以包含多个选项每个选项由一个字节的类型字段和一个字节的长度字段组成。
选项字段是可变长度的每个选项的长度由长度字段指定。常见的选项包括窗口扩大因子、时间戳、最大报文段长度MSS等。
窗口扩大因子选项允许接收方通知发送方它可以支持的窗口大小以便发送方根据该信息调整发送窗口的大小。
时间戳选项用于对报文进行时间戳标记帮助测量往返时间RTT和计算报文的时序。
最大报文段长度MSS选项用于告知对方本地所能接受的最大报文段长度以便发送方在传输数据时进行分段。
除了上述常见选项外还有一些其他的选项如选择确认选项SACK、拥塞控制选项等用于实现更高级的TCP功能和性能优化。
选项字段在TCP报文头部中是可选的不是所有的TCP报文都会使用选项字段。如果使用了选项字段其总长度必须是32位4字节的倍数。
总结起来选项字段是TCP报文头部中的可选字段用于传递一些与特定功能或参数相关的信息。选项字段可以包含多个选项每个选项由一个字节的类型字段和一个字节的长度字段组成。常见的选项包括窗口扩大因子、时间戳、最大报文段长度等用于实现不同的TCP功能和性能优化。选项字段的长度必须是32位的倍数。
TCP特点
有连接,可靠传输,面向字节流,全双工
可靠传输实现机制-确认应答 上述图片展示了TCP传输的确认应答机制,但是为什么要给每一个应答编号呢? 因为此时会出现后发先至的问题 假设我们顺序发送了TCP1和TCP2,接收端在接收到TCP1和TCP2后发送了TCP1的应答和TCP2的应答,但是由于一些原因,使TCP2 的应答先于TCP1的应答,此时会产生错误 此时的解决方法就是给应答增加一个确认序号,确认序号的数值,就是收到的最后一个字节的编号再1 我们通过ACK标记来确认是普通报文,还是返回的应答报文 ACK是0表示这是一个普通报文,此时只有32位序号是有效的,32位确认序号是无效的 ACK是1表示这是一个应答报文,这个报文的序号和确认序号都是有效的 确认报文的序号和正常报文的序号,之间没有关联关系,各自论各自的 确认应答是TCP保证可靠性的最核心的机制,而不是其他
超时重传
在网络上很可能出现发一个数据,然后丢了,这种现象就叫丢包,因为数据在网络上传输会经过很多路由器和交换机,他们是交通枢纽,每个时间通过的数据量也不确定,如果有一个设备太繁忙了,后面的数据等太久了,就可能会被丢弃,此时就会出现丢包
如果真的出现丢包这样的现象,就要通过超时重传这样的机制来确保数据能够正确传输,超时重传,相当于针对确认应答机制,进行重要的补充
针对于TCP,丢包会出现两种情况,一种是发送的数据丢包,一种是返回的确认应答丢包 作为数据的发送方来说,他并不知道是上述的两种情况中的哪一种,此时既然无法区分,数据源在没有等到应答报文,等待一段时间后,就会将数据重新发送一分给接收方
针对于第一种情况,数据本身并没有发送到接收方,此时发送方再重传一份数据,是没有任何问题的,但是如果是第二种情况,实际上发送方的数据已经传输到接收方,此时如果再发送一份数据,此时就会出现数据重复的问题
作为接收方,收到数据后,需要对数据进行去重,把重复的数据丢弃掉,保证应用程序,调用read的时候,读到的数据不会重复,那么如何进行去重呢? 我们可以直接使用TCP的序列号来作为判定依据,TCP会在内核中,给每个socket对象都安排一个内存空间,相当于一个队列,被称为’接收缓冲区’,收到的数据,都会放到接收缓冲区里,并且按照序号排列号顺序了,此时就可以很容易找到此时新收到的数据是否重复了 此时的有序排列,是非常有意义的,这里也解决了在确认应答机制中的后发先至问题,此时就算出现了先发后至问题,应用程序这里读到的数据,仍然是有序的 在数据被读取后,数据就会被默认从队列中删除,此时是一个生产者消费者模型,
接收缓冲区数据有序还可以保证在数据在被读取后删除,此时发送端再发送一条数据,此时就可以通过序号大小来判断此时这个数据是否是被读取到了,就可以实现去重的问题
发送方等待的超时时间是可变的,可以配置的,此时的超时时间并不是一个固定的值,而是会随着超时轮次的增加,而在进一步增加 随着超时重传的轮次增加,等待的时间也会越来越长,正常来说,在第二次重传就会有极大的概率重传成功,如果一个数据经过好几次都没有传输过去,说明大概率是网络出现了很大的问题,此时重传次数到达一定程度,此时就会尝试重置TCP连接,对应TCP报文中的RST字段,此时这个数字为1,就表明要尝试重置TCP连接
如果此时网络已经出现了严重故障,复位操作也没有成功,最终只能放弃连接,就会把自身保存的对端信息就删除掉了
连接管理机制
三次握手
三次握手是客户端服务器建立连接的一个过程 首先客户端向服务器发起一个请求,表示我想要和你建立连接 服务器表示收到,然后返回我也想和你建立连接的一个响应 客户端此时也返回一个收到,此时连接就建立完成了 分别站在客户端和服务器的角度,两者都向对方发起了想和你建立连接的申请,并且都能够得到对方的回应,此时连接就可以建立 SYNSynchronize是TCP连接建立过程中的一个标志位用于同步序列号和进行初始握手。
在TCP三次握手中SYN标志位被用作连接请求方发送的报文段的标识。发送方设置SYN标志位为1表示请求建立连接并携带自己的初始序列号。
具体的握手过程如下 客户端向服务器发送一个包含SYN标志位的SYN报文其中序列号用来标识客户端的起始数据字节序号。服务器在接收到客户端的SYN报文后会发送一个包含SYN和ACK标志位的报文其中SYN标志位仍然为1表示同意建立连接ACK标志位为1确认收到了客户端的SYN请求并携带自己的初始序列号。客户端收到服务器的报文后发送一个ACK报文其中ACK标志位为1表示确认收到了服务器的同意建立连接的报文并携带服务器的初始序列号1。 这样通过三次握手双方完成了连接的建立可以开始进行数据传输。
此处建立连接的过程使用TCP三次握手,主要是为了保证网络通信顺畅,并且验证发送和接收方设备都能够正常运行
为什么必须是三次握手而不是四次或者两次? 两次:两次握手虽然可以验证完成通信能力的验证,但是服务器端并没有接收到客户端发来的ACK应答报文,所以服务器并不知道验证通过的信息 四次:四次是可以完成任务,但是他是将服务器端发送的信息拆分成两次,是没有必要的,拆分成两次,降低了效率 四次挥手
四次挥手是通信双方断开连接的过程
三次握手,必然是由客户端发起的,但是四次挥手则不一定,但大部分还是客户端主动断开连接 这里假设还是客户端发起断开连接的申请 首先客户端发送给服务器断开连接的申请,服务器立马返回一个ACK报文,表示收到 但是这里的断开连接和返回ACK并不是一起的,而是根据服务器端代码的执行逻辑在彻底断开连接 此时客户端在给服务器返回一个ACK,连接彻底关闭 FIN也是六个标志位中的其中一个,FIN为1,表示这是一个结束报文
具体而言TCP四次挥手的过程如下 第一次挥手FINACK 客户端发送一个标志位包含FIN结束标志和ACK确认标志的报文表示客户端已经没有数据需要发送并请求关闭连接。此时客户端进入FIN_WAIT_1状态。 第二次挥手ACK 服务器收到客户端的FIN报文后发送一个仅包含ACK标志的报文作为回应表示它已经收到了客户端的关闭请求。此时服务器进入CLOSE_WAIT状态等待自己的数据发送完毕。 第三次挥手FINACK 当服务器所有的数据都发送完毕后会发送一个标志位包含FIN和ACK的报文表示服务器也没有数据需要发送并准备关闭连接。此时服务器进入LAST_ACK状态。 第四次挥手ACK 客户端收到服务器的FIN报文后发送一个ACK报文作为回应表示已经确认服务器的关闭请求。此时客户端进入TIME_WAIT状态。 最后服务器在收到客户端的确认后会关闭连接此时服务器进入CLOSED状态而客户端则等待一段时间后关闭连接进入CLOSED状态。
为什么必须是四次挥手,而不是三次 因为和三次挥手不同,服务器向客户端返回应答是,两次不一定能够合并,第一次ACK返回的时候,是瞬发的,收到FIN后,就会立马返回ACK,而第二次返回FIN时,需要调用close方法,或者进程结束,才会发送 特殊情况 如果服务器始终没有进行close,客户端的连接就始终不关闭吗? 此时服务器的TCP状态,就处于CLOSE_WAIT状态,站在服务器的角度,虽然这里的连接没有关闭,但是这个链接其实已经不能正常使用了 如果此时对socket进行读操作,如果数据还没读完,可以正常读,读完了就返回EOF 如果此时针对socket进行写操作,就会直接触发异常 站在客户端的角度,如果迟迟收不到对方的FIN,会进行等待,如果一直等不到,就会单方面放弃链接 如果在三次握手和四次挥手的过程中,出现了丢包该如何处理? 这里也是涉及到超时重传机制,三次握手和四次挥手也是带有重传机制的,如果连续重传多次,此时仍会单方面释放连接 丢失第一条 FIN 报文如果客户端发送的第一条 FIN 报文丢失服务器将无法收到关闭连接的请求客户端会等待超时并重新发送第一条 FIN 报文。 丢失第二条 ACK 报文 在服务器确认收到客户端的关闭请求后发送的 ACK 报文如果丢失客户端将一直等待服务器的确认不会进入CLOSE_WAIT 状态。 丢失第三条 FIN 报文 如果服务器发送的第三条 FIN 报文丢失客户端将无法接收到服务器的关闭请求服务器会等待超时并重新发送第三条FIN 报文。 丢失第四条 ACK 报文 在客户端收到来自服务器的关闭请求后发送的 ACK 报文如果丢失客户端将一直等待服务器的确认不会进入TIME_WAIT 状态。 滑动窗口
刚才我们讨论了确认应答策略对每一个发送的数据段都要给一个ACK确认应答。收到ACK后再发送下一个数据段。这样做有一个比较大的缺点就是性能较差。尤其是数据往返的时间较长的时候。. 每次发送数据之后,为了保证可靠性,都要消耗大量的时间来等待ACK,使用滑动窗口就可以缩短上述时间 一次性发出一组数据,发送这一组数据的过程中,不需要等待ACK,此时就相当于一份等待时间等四个ACK,把一次发送多少数据,不用等ACK这样的大小称为窗口 窗口越大,此时批量发送的数据就越多,效率就越高 但是窗口不能无限大,如果是无限大,相当于完全不必等ACK,此时就和不可靠传输差不多 滑动窗口是一个形象的比喻,实际上本质就是批量发送数据,这样可以缩短等待时间,比之前能提升一定的效率但是效率仍没有UDP高 按照滑动窗口的方式来批量发送数据,万一丢包了怎么办? 此时分为两种情况:一种是;数据报丢失,一种是返回的ACK丢失 ACK丢失 ACK如果出现丢失,不用做任何处理,也是正确的,除非是所有ACK都丢了(出现了重大网络故障),否则,只是丢了一部分ACK,对于可靠传输,没有任何影响 因为只要有一个ACK到达,就说明这个ACK之前的数据就全部到达了 数据丢失 如图所示,在1001-2000这段数据丢失后,服务器回一直返回1001这个序号,当返回的ACK连续几次都是1001的话,客户端就知道,1001-2000这段数据丢包了,此时在重新传输1001-2000这段数据,在这之前客户端发送的2001-3000,3001-4000…6001-7000这些数据,就会放在接收方的缓存区里 如果接收缓冲区,这一块少了元素,返回的ACK就会始终索要1001-2000这个数据,一旦这个数据被补上了,此时1001-2000后面的数据就不必重新传输了,这样的操作被称为快速重传,相当于用最小的成本,完成了重传的工作
流量控制
滑动窗口,窗口越大,传输效率越高,但窗口也不能无限大,如果窗口太大了,就可能使接收方处理不过来了,或者是使传输的中间链路出现处理不过来,这样就会出现丢包,此时窗口大不仅没有提高效率,反而还影响了效率
流量控制,就是避免让窗口太大,导致接收方处理不过来 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段通过ACK端通知发送端 窗口大小字段越大说明网络的吞吐量越高 接收端一旦发现自己的缓冲区快满了就会将窗口大小设置成一个更小的值通知给发送端发送端接受到这个窗口之后就会减慢自己的发送速度 如果接收端缓冲区满了就会将窗口置为0这时发送方不再发送数据但是需要定期发送一个窗口探测数据段使接收端把窗口大小告诉发送端。 接收端如何把窗口大小告诉发送端呢 回忆我们的TCP首部中有一个16位窗口字段就是存放了窗口大小信息 那么问题来了16位数字最大表示65535那么TCP窗口最大就是65535字节么 实际上TCP首部40字节选项中还包含了一个窗口扩大因子M实际窗口大小是窗口字段的值左移 M 位 拥塞控制
总的传输效率,是一个不同效应,取决于最短板
虽然TCP有了滑动窗口这个大杀器能够高效可靠的发送大量的数据。但是如果在刚开始阶段就发送大量的数据仍然可能引发问题。 因为网络上有很多的计算机可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下贸然发送大量的数据是很有可能引起雪上加霜的。 TCP引入慢启动机制先发少量的数据探探路摸清当前的网络拥堵状态再决定按照多大的速度传输数据 此处引入一个概念程为拥塞窗口 发送开始的时候定义拥塞窗口大小为1 每次收到一个ACK应答拥塞窗口加1 每次发送数据包的时候将拥塞窗口和接收端主机反馈的窗口大小做比较取较小的值作为实际发送的窗口 像这样的窗口的增长速度,是指数级别的,慢启动只是初始满,但是增长速度非常快 拥塞控制和流量控制,共同限制了滑动窗口机制,可以使滑动窗口,能够在可靠性的前提下,提高传输效率了
延迟应答
延迟应答的作用主要是,在条件允许的基础上,尽可能地提高窗口的大小 假设接收端缓冲区为1M。一次收到了500K的数据如果立刻应答返回的窗口就是500K但实际上可能处理端处理的速度很快10ms之内就把500K数据从缓冲区消费掉了 在这种情况下接收端处理还远没有达到自己的极限即使窗口再放大一些也能处理过 来 如果接收端稍微等一会再应答比如等待200ms再应答那么这个时候返回的窗口大小就是1M 一定要记得窗口越大网络吞吐量就越大传输效率就越高。我们的目标是在保证网络不拥塞的情况下尽量提高传输效率 捎带应答
在延迟应答的基础上我们发现很多情况下客户端服务器在应用层也是 “一发一收” 的。意味着客户端给服务器说了 “How are you”服务器也会给客户端回一个 “Fine, thank you” 那么这个时候ACK就可以搭顺风车和服务器回应的 “Finethank you” 一起回给客户端 延迟ACK发送的时机,尽可能和响应一起返回给客户端,这也是为什么四次挥手有的时候也可以是三次挥手 数据报从两个合并成一个,效率会有明显的提升,主要是因为这里每次传数据都是需要封装分用,能合并的原因,一方面是时机上是可以同时的,另一方面是ACK数据本身不需要携带载荷,和正常的数据也不冲突,完全就可以让一个数据包,即能携带在和数据,又能带有ACK的信息 面向字节流
在面向字节流这样的情况下,会产生一些其他的问题
粘包问题
这里粘的是应用层数据报
通过tcp read或者write的数据,都是tcp报文的载荷,也就是应用层数据 发送方一次性是可以发送多个应用层数据报的,但是接收的时候,如何区分,从哪里到哪里是一个完整的应用数据报,如果没设计好,设计方就很难区分 此处正确的做法是合理的设计应用层协议 应用层协议中,引入分隔符,区分包与包之间的边界 应用层协议中,引入包长度,也能区分包之间的边界 粘包问题不仅仅是tcp才有的,只要是面向字节流的也会有相同的问题,解决方案也相同,要不引入分隔符,要么使用长度 xml/json是通过分隔符来区分包的 protobuffer是通过长度来区分的
TCP异常情况处理
进程崩溃
进程结束表示着PCB没了,文件描述符表也就被释放了,相当于调用了socket.close()
此时崩溃的这一方就会发出FIN,进一步触发四次挥手,此时链接就被正常释放了,此时tcp的处理和进程正常退出,没啥区别
主机关机
正常关机,就会尝试杀死所有进程,此时和进程崩溃的处理方式是相同的
主机关机有一定的时间,如果在这个时间内,四次挥手可能正好结束,但是如果没有挥手结束,也没有问题,此时通过超时重传机制,在重传几次都没有应答以后,就自动单方面释放自己的连接信息了
主机掉电
主机掉电分为两种情况,第一种是发送方主机掉电,一种是接收方主机掉电
接收方掉电
此时情况比较简单,如果是接收方掉电,发送方发送的数据没有收到ACK,此时就会触发超时重传,如果重传仍然失败,就会触发复位报文RST,尝试重新连接,重置操作仍然失败,此时就会单方面释放连接了
发送方掉电
此时的情况就比较复杂 此时接收方一直在等待发送方的消息,此时发送方突然就不发送消息了,此时接收方不知道发送方是暂时不发数据,还是一直就不发了,此时接收方就会阻塞等待 此时就涉及到心跳包,接收方虽然是只需要接收消息,但是也会周期性的给对方发送一个不携带任何业务数据(载荷)的TCP数据报,发起这个数据报的目的,就是为了触发ACK,就是确认一下,发送方是否正常工作,如果此时不能正常返回ACK,说明接收方已经不能发送数据了