`

TCP的数据交互

 
阅读更多

 

小包的交互

如果我们像telnet那样输入字符,则每次都会触发一个小包的传输,可能只有一个字节的数据内容(数据包是20字节的ip头+20字节的tcp头为41字节)。


当三次握手建立后,客户端像服务端发送数据,分别发送G,E,T。

No.40的TCP内容如下:

Transmission Control Protocol,Src Port:1234, Dst Port:80, Seq:1, Ack:1, Len:1

可以看到数据内容长度为1字节。

序号40的时候客户端发送G,可以看到服务端延迟了接近200毫秒后才回了一个ack。

之后客户端又发送了E和T,这次服务端又延迟确认了,两次都是等待100毫秒左右才发回了ack包。 

服务端不会立即确认收到的数据,而是等待一会,如果在这段时间内有数据要发送,则ack和数据一起发送给客户端,这种现象叫捎带ACK

而如果在这段时间之内没有数据发送,则会等待超时后发回一个ack。一般linux系统为40毫秒,《TCP/IP详解》里面介绍的是早期的linux版本为200毫秒,最大的延迟不应该超过500毫秒。

 

 

 

Nagle算法

因为在广域网上发送1字节内容的小包很不划算浪费带宽。所以该算法规定最多只能有一个未被确认的小分组,在该分组的确认达到之前不能发送其他小分组。相反,TCP手机这些少量的分组,并在确认到来时以一个分组的方式发出去。

该算法的优越之处在于它是自适应的:确认达到的越快,数据发送的越快。

伪代码如下:

if there is new data to send
  if the window size >= MSS and available data is >= MSS
    send complete MSS segment now
  else
    if there is unconfirmed data still in the pipe
      enqueue data in the buffer until an acknowledge is received
    else
      send data immediately
    end if
  end if
end if

 API必须提供TCP_NODELAY选项来关闭nagle算法

对于交互性很强的X窗口来说,应当关闭nagle算法,否则用户会感到明显的延迟。

 

对于

write(head);
write(body);
read();

 这种代码,就会触发nagle算法,第一个write(head)发送后,服务端还没有来得及确认(捎带ACK),需要等回复的的数据+ACK一起确认给客户端,而客户端发送给服务端的数据是不完整的,只有head,没有body。服务端的应用层需要等待body才能处理,这样就导致了延迟确认,其情况类似第一个截图。

其过程是:(如果是debug的话,最终的现象是客户端会在read()那里卡住一小会)

1.客户端发送head

2.服务端只收到了head,等待body

3.客户端继续发送body,但此时没有等待服务端的ack,于是将body放到缓存队列中,延迟发送(如果body

   很大则会立刻发送)

4.服务端等待超时,发送了一个ack确认给客户端(对head的确认)

5.客户端收到确认后,将剩下的body发送给服务端

6.服务端收到body后,应用层可以继续处理逻辑了,处理完后将结果发给客户端

7.客户端收到结果后继续执行或者可以打印出结果

 

如果将两个write()合并在一起,做成一个完成的数据发送给服务端,这样服务端应用层就看以处理了,处理完之后就会返回,这样就不会出现延迟确认了,服务端每次收到的都是完整的数据,可以立刻处理并返回,同样客户端read()的时候也不会卡主了。


这里就没有延迟了

 

 

 

数据的确认和MSS

如果是单独发送一个ack,ack的序号是syn+len,也就是发送方的序列号+发送的字节长度

发送方发送的序号为4206382601,len为13,接收方确认的ack为4206382614

如果是捎带ACK也是一样的。

MSS的含义是最大报文段长度,以太网最大数据长度是1500字节,所以MSS最多只能是1460字节(去掉20字节的IP首部和20字节的TCP首部)。理论上TCP是上层的它不用关心底层是如果分片的,这个分片是由IP层去做的,IP将数据发片后叫给链路层再发送,TCP之所以需要有MSS自己做分片,甚至有些违反了上层知道底层数据大小这么一个细节,是从性能上考虑的。

比如要发送一个10K的数据,作为一个报文段发送,那么最终到链路层会分成很多帧,如果TCP不做分片的话,假设其中一个帧丢失了,那么对方会要求重传,这样发送端不得不重新发送者10K的数据,严重浪费了带宽。而如果TCP自己分片的话,只需要发送丢失的那个报文段即可。

 

 

 

 

滑动窗口


缓冲窗口可以告知发送方,接收方能接收的数据量大小。当窗口为0时,接收方就不能发送数据了。

这里也会引发很多很多,比如糊涂窗口综合征,窗口本来很大,但是接收方处理不过来,告知发送方窗口为一个较小的值,最后发送发每次都发送小包。

使用三个术语来描述窗口左右边沿的运动:

1.称窗口左边沿向右边沿靠近为窗口合拢。这种现象发生在数据被发送和确认时。

2.当窗口右右边沿向右移动时将允许发送更多的数据,我们称之为窗口张开。这种现象发生在另一端的

   接收进程读取已经确认的数据并释放了TCP的接收缓存时。

3.当右边沿向左移动时,我们称之为窗口的收缩,RFC强烈建议不要使用这种方式。

 

这里有一个例子,客户端<---->服务端,客户端发送helloworld,服务端回显helloworld。

同时故意把发送和接收缓冲区设置很小,截图如下:


打红框的是IP尾数为116的机器,116向尾数为133的机器发送helloworld,然后133回显将同样的内容发给166,由于166接收不过来了,可以看到166的滑动窗口慢慢变小,也就是窗口左边慢慢向右移动。如果窗口变为0了则表示接收不过来了,133就无法发送数据了。

 

滑动窗口可以的控制可以分成三种

1.停-等协议(1比特协议),这种情况下发送方和接收方的窗口都是1,每次都必须发送一个字节,然后等待确认再发送,发送方和接收方的状态图如下:


发送方有一个发送超时设置,当一个数据包经过一段时间之后没有收到ACK,就重新发送。
 

2.后退N协议

停等协议无疑效率很低。后退N协议是发送一个报文段后不等待确认,继续发送数据,而且在每发送完一个报文段后都设置一个定时器,在一段时间内收不到确认的ack,就重新发送这个报文段。

比如发送方一口气发送了1--10个报文段,而报文段3接收出错或者没有收到ack,则必须重新发送3-10这几个报文段。在网络不佳的情况下,后退N协议反而会对网络造成更大的拥塞。

 

3.选择重传协议

后退N协议在网络很差的时候会造成网络拥塞,接收方收到1-3这几个报文段,又收到了5-10这几个报文段。此时如果按照后退N协议发送方就会重发4-10这几个报文段。选择重传协议可以让接收方通告发送方,只重传出错的报文段4即可。但是这必须要求接收方有更多的缓冲区可以存下更多的报文段。等这些报文段都达到后一起交给应用层。

 

发送端和接收端的滑动窗口交互过程


 

 

 

 

坚持定时器(persist timer)

如果接收方的窗口已经满了,会通告发送方一个窗口为0的确认报文段,这样发送方将不再发送数据。之后接收方处理完逻辑之后窗口又打开了可以接收数据了,便向发送方发一个非0窗口的确认报文段。如果这个确认报文段丢失会怎样?

发送方等待接收一个非0的窗口确认,这样好发送数据;而接收方此时窗口大于0了可以接收数据了,但是发送方却不知道,双方进入死锁状态。

为了防止这种情况,发送方使用一个坚持定时器(persist timer)来周期性的向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文段称之为窗口探查(window probe)。


 上图中,发送方75.1每隔一秒都会发送一个窗口探查,接收端75.132会返回一个确认报文,告诉发送方此时窗口大小为0,发送方仍旧不能发送数据。直到窗口大于0发送方才可以继续发送数据。

 

 

 

糊涂窗口综合征(silly window syndrome)

基于窗口流量控制方案,可能会导致接收方每次都通告一个小窗口,比如窗口大小为1,这样发送方仍然发送数据,但是报文段长41(20字节的IP头和20字节的TCP首部以及1字节的数据)。这样对带宽浪费很大,这种现象可以在两端中的任何一端

1.如果是接收端引起的;那么如果接收到的数据导致窗口小于某个值,直接发送一个窗口为0的ack,这样就阻止发送端继续发数据了。等到接收端处理完一些数据了,窗口size大于等于MSS或者,缓冲区中有一半为空,就可以发送一个非0窗口让发送方继续发送数据。

2.如果是发送端引起的;那么使用nagle算法,有两个条件:

    1)等到窗口size大于等于MSS或者发送数据size大于等于MSS

    2)等待时间超过200毫秒

    当满足两个条件之一时就发送数据,否则就继攒数据,到一定量再发送。

 

 

 

紧急指针

    TCP提供了"紧急方式"(urgent mode),它使一段可以告诉另一端有些具有某种方式的"紧急数据"已经放置在普通的数据流中。另一端被通知这个紧急数据已被放置在普通数据流中,由接收方决定如何处理。

    可以通过设置TCP首部中的两个字段来发出这种从一端到另一端的紧急数据已经被放置在数据流中的通知。URG比特被置为1,并且一个16bit的紧急指针被置为一个正的偏移量,该偏移量必须与TCP首部中的序号字段相加,以便得出紧急数据的最后一个字节的序号。

    只要从接收方当前读取位置到紧急数据指针之间有数据存在,就认为应用程序处于“紧急方式”。在紧急指针通过之后,应用程序便转回到正常方式。

   不幸的是,需要实现不正确的称TCP紧急方式为带外数据(out-of-band data).

   在接收端通告了一个0窗口后,发送方不能发送任何数据,但是可以发送紧急指针和URG标志。

 

 

PUSH标志

对于客户端来说,这个标志通告TCP在向服务端发送一个报文段时,不要因等待额外数据而使已提交数据在

  缓存中滞留。

对于服务端来说,这个标志通告TCP需要立即将这些数据递交给服务端进程而不能等待判断是否还会有额外

  的数据达到。

通过程序模拟一个GET请求给baidu,由于返回的HTML内容远超过了MSS大小,所以数据需要分组,在客户端收到之后需要将多个小分组合并。


TCP自己有MSS(Maximum Segment Size 最大报文段长度),这个长度是小于MTU的(Maximum Transmission Unit最大传输单元)。

这里相当于服务端发送一个大数据,超过了MSS,于是在TCP这层就做了分片,将数据拆成了若干个小包,每个小包都是小于等于MSS的,注意这里并不会使用到IP层的分片,对于IP来说每个数据包都是完成的,只有UDP需要IP层做分片,TCP层自己就可以做了。

对于UDP的组装是需要IP层去组装的,而TCP层是不需要IP层组装,TCP层自己有一个PSH标志,当最后一个分片的数据被接收到后,带有了PSH标志的数据会告知不要缓存全部交给应用层处理。而TCP在发送的时候每个序列号都是递增的,所以可以根据序列号确定谁在前谁在后。

当收到了A1,A2,A3,B1,B2,B3,A4这些数据包后,因为A是先发送的,所以A4的序列号一定是小于B1的,而A4的数据包中还会附带PSH标志,这样就之前收到的A1,A2,A3和A4一起交给了应用层。


从这个截图可以看到,IP层没有偏移量,所以不是IP层分片的,同时这是A这个大数据的最后一个分片,所以TCP层带了一个PSH标志。

 

 

 

参考:

Nagle's algorithm

Nagle算法

Nagle算法TCP_NODELAY和TCP_CORK

网络编程中Nagle算法和Delayed ACK的测试

TCP滑动窗口演示

Sliding Window演示

TCP滑动窗口

TCP/IP中的拥塞窗口

滑动窗口

TCP的那些事儿(上)

TCP的那些事儿(下)

 

 

 

  • 大小: 103.6 KB
  • 大小: 144.1 KB
  • 大小: 54.5 KB
  • 大小: 17.7 KB
  • 大小: 147.3 KB
  • 大小: 23.5 KB
  • 大小: 182.9 KB
  • 大小: 120.6 KB
  • 大小: 62.9 KB
  • 大小: 105.2 KB
分享到:
评论

相关推荐

    TCP调试助手-源代码,跟单片机进行TCP数据交互,接收单片机的数据进行IO显示

    TCP调试助手-源代码,,跟单片机进行TCP数据交互,接收单片机的数据进行IO显示,还有对单片机进行测试电机运动接口,方便简单的保存16进制的IO值,及输入模拟量保存为16进制的模拟量,不需要去计算器换算了,工控人...

    TCP调试助手的exe程序,跟单片机进行TCP数据交互,免费下载 免费下载

    TCP调试助手打包的exe程序,跟单片机进行TCP数据交互,接收单片机的数据进行IO显示,还有对单片机进行测试电机运动接口,方便简单的保存16进制的IO值,及输入模拟量保存为16进制的模拟量,不需要去计算器换算了,...

    C#实现soket、tcp上位机与下位机数据交互框架.rar

    总结来说,C#实现的Socket和TCP数据交互框架是基于网络编程基础,通过Socket对象与下位机建立连接,利用TCP的可靠性传输数据。开发者需要关注连接管理、并发处理、数据封装、错误处理和安全性等多个方面,以确保系统...

    labview以太网的TCP数据采集

    在“labview以太网的TCP数据采集”这一主题中,我们将深入探讨如何利用LabVIEW与TCP(Transmission Control Protocol)网络协议进行数据交互,从而实现以太网上的数据采集。 TCP是一种面向连接的、可靠的传输层协议...

    Android应用源码http、udp、tcp网络交互组件.rar

    2. TCP连接模块:创建Socket,通过输入输出流进行数据交互,可能包含连接管理、错误处理等。 3. UDP通信模块:创建DatagramSocket,发送和接收DatagramPacket,处理数据包的封装和解封装。 4. 可能还有网络状态监听...

    C# TCP 请求交互 TCPServer and TCP-Clent

    - **数据传输**:同样,使用TcpClient的GetStream()方法获取NetworkStream,并通过其Read()和Write()方法进行数据交互。客户端通常发起请求并接收服务器的响应。 - **断开连接**:完成数据传输后,客户端也需要...

    昆仑通态(MCGS)嵌入版ModBusTcp数据转发设备驱动.rar

    这样,用户无需关心底层网络细节,只需在MCGS界面操作,即可实现与远程设备的数据交互。 使用这个驱动时,首先要确保MCGS嵌入版已经正确安装,并且具备配置数据转发的能力。用户需要设置数据转发规则,包括指定本地...

    TCP工具,TCP数据收发

    本文将深入探讨标题为"TCP工具,TCP数据收发"的工具及其相关知识点,以及与之相关的标签。 首先,这个工具集成了多种通信和加密功能,旨在提供全面的桌面开发支持。它不仅包含了基本的TCP功能,还涵盖了串口收发,...

    EC20_单片机串口1透传TCP数据DTU

    EC20_单片机串口1透传TCP数据...总结来说,EC20_单片机串口1透传TCP数据DTU项目是STM32F407和EC20模块结合使用,构建了一种强大的串口到网络的数据传输解决方案,它在各种需要实时数据交互的场景中具有广泛的应用前景。

    Android应用源码http、udp、tcp网络交互组件

    在Android应用开发中,网络交互是至关重要的组成部分,它使得应用程序能够与远程服务器进行数据交换,从而实现各种功能,如获取在线数据、上传用户信息、实时通信等。本项目"Android应用源码http、udp、tcp网络交互...

    STM32以太网TCP服务器收发数据实验

    对于数据的发送和接收,STM32通过调用lwIP的API与TCP服务器进行交互。要发送数据,可以使用`tcp_write()`函数,它将数据写入TCP发送缓冲区。接收数据则通过`tcp_recv()`函数,当数据到达时,lwIP会回调预定义的接收...

    TCP_Client.rar_tcp 交互_连接服务器

    在IT行业中,TCP(传输控制协议)是一种广泛用于网络通信的协议,它是互联网协议栈(TCP/IP协议族)的重要...在实际编程中,开发者需要熟悉如何使用TCP套接字API来实现客户端功能,以便有效地与服务器进行数据交互。

    php硬件tcp交互crc8循环校验码

    php硬件tcp交互crc8循环校验码;本人亲自用过可用。应用场景,php语言搭建tcpserver与硬件实现tcp交互。其中用到了crc8校验码。里面用到了使用pack打包数据,获取crc8校验码

    TCP.rar_C# TCP传输_C#的TCP通信_tcp vs2008_tcp数据通信_数据传输

    本文将深入探讨C#语言在VS2008环境下实现TCP异步通信的方法,以及TCP数据传输的相关知识。 首先,TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。它通过三次握手建立连接,确保数据在传输前双方已建立...

    TCP服务端客户端交互

    本实验“TCP服务端客户端交互”旨在通过实践来理解TCP服务端和客户端如何进行数据通信,以及如何实现回射(echo)功能,即服务端接收到客户端发送的数据后,原样返回给客户端。 首先,TCP是一种面向连接的、可靠的...

    触摸屏数据TCP转发设置教程

    通过以上步骤,我们可以成功地实现触摸屏数据的TCP转发设置,使触摸屏与上位机之间能够顺畅地进行数据交互。这对于工业自动化控制系统的构建具有重要意义。初学者可以通过本教程的实际操作练习,更好地理解和掌握这...

    AS3+JAVA网游开发数据交互源码.rar

    在网游中,数据交互通常通过网络协议(如TCP或UDP)实现。客户端向服务器发送请求,服务器处理后返回响应。这个过程中可能涉及序列化和反序列化,以将数据结构转换为在网络上传输的字节流。 4. **源码分析** 这个...

    TCP交互模块

    在这个TCP交互模块中,开发者利用mina提供的API创建了一个TCP服务器端,它可以接收来自客户端的连接请求,处理数据传输。服务端通常会包含一个Acceptor对象,用于监听指定端口的连接,并在接收到连接请求时创建一个...

    C语言实现TCP服务端与客户端交互

    在TCP交互过程中,数据的传输是通过多个数据段进行的,每个数据段都包含序号和确认号,以确保数据的正确传输。同时,TCP还提供流量控制和拥塞控制机制,防止数据丢失或拥塞。 实现TCP服务端与客户端的交互时,需要...

    应用源码http、udp、tcp网络交互组件.zip

    在Android开发中,网络通信是应用与服务器交互的基础,HTTP、UDP和TCP是三种常见的网络传输协议。这个压缩包文件“应用源码http、udp、tcp网络交互组件.zip”提供了有关这三种协议在Android环境下的源码实现,是学习...

Global site tag (gtag.js) - Google Analytics