【网络协议笔记】第四层:传输层(Transport)TCP协议简介(1)
TCP有以下几个知识点。图片备用地址图片备用地址TCP的几个要点:可靠传输、流量控制、拥塞控制、连接管理(建立和释放连接)。也正因为这几点使得首部变得很复杂。占4位,取值范围是0x0101 ~ 0x1111。乘以4就是首部长度(Header Length)。所以取值范围是5 ~ 60字节,由于首部固定部分占用20字节,所以可选部分至多占用40字节(和网络层首部一样)。为什么叫数据偏移?因为相对TCP报文向右偏移首部长度后就是数据部分。UDP的首部中有个16位的字段记录了整个UDP报文段的长度(首部 + 数据)。但是,TCP的首部中仅仅有个4位的字段记录了TCP报文段的首部长度,并没有字段记录TCP报文段的数据长度。分析:UDP首部中占16位的长度字段是冗余的,纯粹是为了保证首部是32bit对齐。TCP/UDP的数据长度,完全可以由IP数据包的首部推测出来,传输层的数据长度 = 网络层的总长度 - 网络层的首部长度 - 传输层的首部长度。占6位,目前全为0。与UDP一样,TCP检验和的计算内容:伪首部 + 首部 + 数据。伪首部占用12字节,仅在计算检验和时起作用,并不会传递给网络层。图片备用地址一共占6位或9位。有些资料中,TCP首部的保留(Reserved)字段占3位,标志(Flags)字段占9位。Wireshark中也是如此。是因为标志位中的前3位是无用的,所以两种说法都不能说是错的。图片备用地址图片备用地址意思:紧急。当URG=1时,紧急指针字段才有效。表明当前报文段中有紧急数据,应优先尽快传送。紧急指针存放的是长度值,表示TCP的前多少字节是需要紧急优先处理的。意思:确认。当ACK=1时,确认号字段才有效。意思:推。一般用在交互式网络中。PUSH标志位所表达的是发送方通知接收方传输层应该尽快的将这个报文段交给应用层。意思:重置。当RST=1时,表明连接中出现严重差错,必须释放连接,然后再重新建立连接。意思:同步。当SYN=1 & ACK=0时,表明这是一个建立连接的请求。若对方同意建立连接,则回复SYN=1 & ACK=1。请求方再发送SYN=0 & ACK=1时表明开始传输数据。这也是三次握手的流程。意思:完成。表明数据已经发送完毕,要求释放连接。占4字节。首先,传输的每一个字节都会有一个编号(连续的字节编号也是连续的)。在建立连接后,序号代表这一次传给对方的TCP数据部分的第一个字节的编号。占4字节。在建立连接后,确认号代表期望对方下一次传过来的TCP数据部分的第一个字节的编号。占2字节。这个字段有流量控制功能,用以告知对方下一次允许发送的数据大小(字节为单位)。ARQ(Automatic Repeat-reQuest), 自动重传请求。图片备用地址无差错情况A发送数据M1到B,B收到数据M1后向A发送确认信号M1;A收到确认信号M1后,继续向B发送数据M2,B接收后向A发送确认信号M2。超时重传A发送数据M1到B,A在发送数据途中丢包或B发现数据M1有错误直接丢掉,导致B无法向A发送确认信号M1;A在一定时间间隔后发现没有收到B发送的确认信号M1,A会继续向B发送数据M1;B收到数据M1后向A发送确认信号M1,A收到确认信号M1后,继续向B发送M2数据。通过确认与超时重传机制实现可靠传输,在发送完一个分组后,必须暂时保留已发送的分组的副本。分组和确认分组都必须进行编号。超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些。图片备用地址确认丢失A发送数据M1到B,B接收到数据M1后,向A发送确认信号M1;B在向A发送确认信号M1中途丢包,此时A在一定时间间隔后发现没有收到B发送的确认信号M1,A会继续向B发送数据M1;B收到数据M1后会丢弃重复的数据M1(之前已经收到数据M1,只是A不知道),继续向A发送确认信号M1;A收到确认信号M1后,继续开始发送M2数据。确认迟到A发送数据M1到B,B接收到数据M1后,向A发送确认信号M1;B在向A发送确认信号M1时,由于网络延迟等原因导致A在一定时间段内未收到确认信号;A会继续向B发送数据M1,B收到数据M1后丢弃重复的数据M1,并向A发送确认信号M1;A收到确认信号M1后,继续开始发送M2数据,M2数据刚发送出去,此时A刚好接收到B在第一次发送的确认信号M1,但由于之前已经成功接收并处理了第二次的确认信号M1,所以A在收到确认信号后什么也不做。出现差错或丢失的时候,发送方会将自己备份的副本再重传一次,直到收到接收的确认信息。当接收方收到重复的数据时,会直接丢弃,但是会给发送方请确认自己已经收到了。上面的停止等待协议每发送一组数据就必须等到接收方回复确认后,再发起第二组数据,如果出现超时重传的话,效率更低。因此为了提高传输的效率,改进了等待传输协议。连续ARQ协议和滑动窗口协议的机制是以接收方回复确认为单位,每次连续发送一个滑动窗口指定的数据组。图片备用地址A发送数据给B时,一次性发送M1~M4(A和B建立连接时,B告诉A自己的缓存池可以容纳多少字节数据,A根据这个缓存池的大小构建一个同大小的发送窗口–也可以理解为发送缓存池),此时A开始等待确认,B收到全部数据后会向A发送确认信号M4(以最后一个编号为准);A收到确认信号后,继续向B发送M5 M8(A把之前构建的窗口滑动并锁定到对应大小的数据段上,即M5 M8),以此往复直到数据传输完毕。如果接收窗口最多能接收4个包(窗口大小),但发送方只发了2个包,接收方如何确定后面还有没有2个包?答案:接收方会在等待一定时间后发现没有第3个包,就会返回收到2个包的确认信号给发送方。滑动窗口是由发送方维护的类似指针的变量,在每收到一个接收方的确认消息后,该指针向前移动并发送数据,到窗口指定大小的数据组时停下,等待接收方的确认。图片备用地址累积确认机制: 发送方不对收到的分组逐个发送确认,而是对按序到达的最后一个分组发送确认,这样就表示:到这个分组为止的所有分组都已正确收到了。优点:容易实现,即使确认丢失也不必重传。缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。Go-back-N(回退 N): 为了解决上述同一窗口中数据组不能完整确认的问题,连续ARQ协议采用了回退机制。比如说:发送方发送了前5个分组,而中间的第3个分组丢失了。这时接收方只能对前两个分组发出确认。发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次。这就叫做 Go-back-N(回退 N),表示需要再退回来重传已发送过的N个分组。结论:当通信线路质量不好时,连续ARQ协议会带来负面的影响。可能还不如传统的停止等待协议。TCP连接的每一端都必须设有两个窗口——一个发送窗口和一个接收窗口。TCP的可靠传输机制用字节的序号进行控制。TCP所有的确认都是基于序号而不是基于报文段。TCP两端的四个窗口经常处于动态变化之中。TCP连接的往返时间RTT也不是固定不变的。需要使用特定的算法估算较为合理的重传时间。滑动窗口是面向字节流的,为了方便记住每个分组的序号,现在假设有一个1200字节的数据,分12组,每一组数据是100个字节,代表一个数据段的数据(每一个数据都有自己的TCP首部),每一组给一个编号(1~12)。图片备用地址图片备用地址TCP通信时,如果发送序列中间某个数据包丢失,TCP会通过重传最后确认的分组后续的分组,这样原先已经正确传输的分组也可能重复发送,降低了TCP性能。SACK(Selective Acknowledgment,选择确认)技术,使TCP只重新发送丢失的包,不用发送后续所有的分组,而且提供相应机制使接收方能告诉发送方哪些数据丢失,哪些数据已经提前收到等。在建立TCP连接时,就要在TCP首部的选项中加上“允许SACK”的选项,而双方必须都事先商定好。原来首部中的“确认号字段”的用法仍然不变。只是以后在TCP报文段的首部中都增加了SACK选项,以便报告收到的不连续的字节块的边界。图片备用地址Kind:占1个字节,值为5代表这是SACK选项。Length:占1个字节,表明SACK选项一共占用多少字节。Left Edge:占4个字节,左边界。Right Edge:占4个字节,右边界。图片备用地址上图的着色模块代表已接收数据,空白代表未接收数据。左右边界意思是会把未接收完毕的TCP数据包的已接收数据进行左右标记。由于TCP的选项不能超过40个字节,去除Kind和Length占用的2个字节,还剩下38个字节给左右边界使用。一组边界占用8个字节(左右边界各占4个字节),所以边界不能超过4组。也能够因此推断出SACK选项的最大占用字节数是4 * 8 + 2 = 34。思考:超过选项边界的数据怎么办?超过边界的数据需要重新传输,但这已经很大程度提高了传输效率。重传机制是TCP中最重要和最复杂的问题之一。TCP每发送一个报文段,就对这个报文段设置一次计时器。只要计时器设置的重传时间到但还没有收到确认,就要重传这一报文段。那么这个重传时间到底应该设置多少呢?建议跳过,有兴趣的可以去查阅相关资料。图片备用地址为什么选择在传输层就将数据分割成多个段,而不是等到网络层再分片传递给数据链路层?-->网络层没有可靠传输协议,丢包无法只发送一个报文段,所以需要分割成多个段。如果在传输层不分段,一旦出现数据丢失,整个传输层的数据都得重传如果在传输层分段了,一旦出现数据丢失,只需要重传丢失的那些段即可欢迎大家的意见和交流email: li_mingxie@163.com

TCP 的优化
整理自 CSDN 公众号1. 客户端TCP 三次握手的开始是客户端发起 SYN,如果服务端没有及时回复,那么会重传,重传的间隔和次数是可控的,默认是五次,第一次间隔 1 秒,第二次 2 秒,第三次 4 秒,第四次 8 秒,第五次16 秒,最终超时时间是 63 秒,因此在优化时可以修改重传次数和间隔,以尽快把错误暴露给应用程序。2. 服务端的半连接队列优化服务端在第一次返回 SYN + ACK 时,就会把这次请求维护进一个半连接队列,这个队列用来维护尚未完成的握手信息(相对于全连接),如果这个队列溢出了,服务端就无法继续接受新的请求了,这也是 SYN Flood 攻击的点。通过一个命令 netstat -s 可以得到累计的、由于半连接队列已满引发的失败次数,隔几秒执行一次就可以知道这个次数是否有上升的趋势以及分析是否正常。这种 SYN Flood 攻击之所以成立,是因为维护这个半连接队列一定要分配一定的内存资源,那么应对的方式之一 syncookies 就是如何不分配资源的前提下,可以确认是一次有效的连接并 establish。syncookies 的工作原理是,服务器使用一种算法,计算出一个哈希值,它包含了客户端发来请求的部分信息,再将这个哈希值和 SYN+ACK 一起返回给客户端,客户端也经过一些运算,再返回给服务端,那么服务端根据这个返回值和之前的计算值比较,如果合法,就可以建立有效连接,从而不会占据半连接队列的内存。应对 SYN 攻击时,只需将 syncookies 的参数值调为 1(半连接队列溢出时启用),即可。相当的,可以增大半连接队列,但是要和 accept 的队列同时增大才有效,(否则会导致 accept 队列溢出同样丢失 TCP 连接)此时,对于客户端来说已经是 established 状态,但是还要再返回给服务端一个 ACK,服务端收到后,服务端才是 established 状态并开始传数据,如果网络不稳定,同样的,服务端会重发 SYN+ACK,当网络不稳定时,应该增加服务端重发 SYN+ACK 的次数。3. 服务端的 accept 队列优化当连接已经建立、应用程序尚未调用时,TCP 连接会被保存在一个 accept 队列中,如果进程未能及时调用,就会导致 accept 队列溢出,溢出部分连接将被默认丢弃。对此可以做的是,选择向客户端发送 RST 报文,告知关闭这个连接,丢弃握手过程。打开这一功能需要将 tcp_abort_on_overflow 参数设置为 1。如果想让客户端了解是由于 accept 队列溢出造成连接失败可以这样做。当 tcp_abort_on_overflow 参数设置为 0 时,则如果 accept 队列溢出,就会丢弃客户端传来的 ACK(用于最后一次握手)。应对高并发流量时,更好的选择是 tcp_abort_on_overflow 参数设置为 0,这样对于客户端它的状态仍然是 established,客户端会定时发送带有 ack 报文的发送数据请求,一旦服务端的 accept 队列有空位,那么连接仍有可能建立成功。所以只有很确定在一段时间内 accept 都是将溢出的状态,才推荐 tcp_abort_on_overflow 参数设置为 1。同样的,可以调整 accept 队列长度,也可以查看累计的由于溢出导致丢失的连接总数,来判断趋势。在 Linux 3.7 内核版本之后,提供了 TCP Fast Open 功能,这个功能如此生效:初次建立 TCP 连接时,客户端在第一个 SYN 包中传入一个请求 cookie,表明打开 fast open 功能,服务端对应生成一个 cookie 给客户端,除此之外,三次握手没有不同,但是,在 cookie 没有过期之前,下一次再连接的时候,客户端发送带有 cookie 的 SYN 包,服务端校验了 cookie 有效以后,就可以开始传输数据了,从而节约了一个往返的时间消耗。TCP Fast Open 功能需要服务端和客户端同时打开才能生效。(备注一个之前看到差点忘了的知识点。当主动方收到被动方的 FIN 报文后,内核会回复 ACK 报文给被动方,同时主动方的连接状态由 FIN_WAIT2 变为 TIME_WAIT,在 Linux 系统下大约等待 1 分钟后,TIME_WAIT 状态的连接才会彻底关闭。1. 主动方的优化关闭的方式有两种 RST 和 FIN,RST 是暴力关闭连接的方式,安全关闭连接则必须四次挥手。FIN 报文关闭则可以使用 close 和 shutdown 两种函数来实现。close 相对来说是“不优雅”的,调用 close 的一方的连接叫做「孤儿连接」,会同时关闭读和写,而 shutdown 可以控制是读还是写。关闭读的时候,会丢弃接收缓冲区里的所有数据,如果后续再接受到数据,也会悄悄丢弃,并发送 ACK,对方不会知道被丢弃了。关闭写的时候,会把发送缓冲区的数据全部发送并发送 FIN。(1)FIN_WAIT1 的优化主动方发送 FIN 以后,进入 FIN_WAIT1 状态,如果迟迟没收到 ACK,会定时重发 FIN,重发次数由 tcp_orphan_retries 参数控制,默认为 8 次,如果处于 FIN_WAIT1 状态的连接过多,应该考虑降低次数,重发次数超过参数时,连接会被直接关闭。如果遇到恶意攻击,可能无法发送出 FIN,因为 TCP 按顺序发送所有包, FIN 也不能绕过,另外如果对方的接收窗口已经满了,发送方也无法再发送数据。此时应该做的是调整 tcp_max_orphans 参数,它定义了「孤儿连接」的最大数量,当系统中的孤儿连接超过参数值,新增的孤儿连接不会再处于 FIN_WAIT1 状态,而是会被 RST 报文直接关闭。(只会影响 CLOSE 函数关闭的连接,不会影响 shutdown 关闭的,不会影响还有读或写的可能)(2)FIN_WAIT2 的优化主动方收到 ACK 后,会处于 FIN_WAIT2,因为被动方还可能有数据发送,如果是 shutdown 关闭,那它也可能还会发送数据,但是对于 close 关闭的连接,无法再发送和接收数据,保持在 FIN_WAIT2 的状态已经没有太大意义,tcp_fin_timeout 控制了这个状态下连接的持续时长,默认值是 60 秒。这个时间和 TIME_WAIT 状态时长是一致的。(3)TIME_WAIT 的优化TIME_WAIT 和 FIN_WAIT2 的时间是一致的,都是 2MSL,1MSL 表示一个报文在网络中存活的最长时间(报文每经过一次路由器的转发,IP 头部的 TTL 字段就会减 1,减到 0 时报文就被丢弃,这就限制了报文的最长存活时间),那么为什么是等待 2MSL 呢,其实就是允许报文至少丢失一次、再发送一次,这样第一个丢失了,等待的时间里第二个 ACK 还会到达,为什么不是 4MSL 以上呢,这是一个概率的问题,如果一个网络丢包率达到 1%,那么连续两次丢包的概率是万分之一,不必为了这种概率增加等待的时长。TIME_WAIT 有存在的意义,但是太多保持在这种状态的连接会占用双方资源,占据客户端的端口资源和服务端的系统资源。Linux 提供了 tcp_max_tw_buckets 参数,当 TIME_WAIT 的连接数量超过该参数时,新关闭的连接就不再经历 TIME_WAIT 而直接关闭。这个参数的设定应该取一个平衡点,即既不会太少导致高并发时产生连接间数据错乱的问题,也不会太多而导致耗尽端口和线程资源。对于用户端来讲,还可以启用 tcp_tw_reuse 参数来复用处于 TIME_WAIT 状态的连接(来节约接口资源。)这个参数有几个前提,一个是只有客户端可以打开,一个是 TIME_WAIT 状态也要保持 1 秒,另一个是要同步打开时间戳功能,报文带上时间戳就可以避免没有了 2MSL 时长以后的混乱情况,时间戳过期的报文就会被丢掉。另外对于 TIME_WAIT,还可以调整 socket 选项,来达到调用 close 关闭连接时跳过四次挥手直接关闭的效果,但不推荐。2. 被动方的优化首先,被动方收到 FIN 时,会自动回复 ACK,接着等待应用程序调用 close/shutdown 来结束连接,再发送 FIN。如果系统中同时查看到多个连接处于 CLOSE_WAIT 状态,则需要排查是否是应用程序出了故障。然后,当被动方也发送了 FIN 以后,还需要等待主动方回复一个 ACK,如果迟迟没收到,也会重发 FIN,重发次数也是 tcp_orphan_retries 参数控制,这点和主动方的优化一致,可以调整次数。(需确认被动方是否有 tcp_max_orphans 参数)3. 如果双方同时关闭?1.ACK 延迟目前在 TCP 中每传输一个报文都要求接收方进行确认,大量短而频繁的确认报文给网络带来了很多开销。因此采取了延迟 ACK 策略来减少 ACK 的数量,就是接收方收到一个报文以后,不会立即发送 ACK,而是等待 1~200ms,这期间若有回送数据报文就捎带确认,但收到两个连续数据报文或者等待超时则发送一个独立确认。有效减少了 ACK 的数量,改善了 TCP 的整体性能。2. 滑动窗口接收方的接收缓冲区不是不变的,接收到新的会变小,应用程序取出后又会变大,因此接收方会把自己当前的接收窗口大小放在 TCP 头告知发送方,如果不考虑拥塞控制,发送方的窗口大小「约等于」接收方的窗口大小。对于这一点,可以把 tcp_window_scaling 配置设为 1(默认打开)来扩大 TCP 通告窗口至 1G 大小。要使用这一选项,需要主动方在 SYN 中先告知,被动方在 SYN 中再反馈。但是缓冲区并非越大越好,还要考虑网络吞吐的能力。如果缓冲区与网络传输能力匹配,那么缓冲区的利用率就达到了最大化。3. 调整缓冲区大小这里需要说一个概念,就是带宽时延积,它决定网络中飞行报文的大小,它的计算方式:(1)发送缓冲区的调整发送缓冲区是自行调节的,当发送方发送的数据被确认后,并且没有新的数据要发送,就会把发送缓冲区的内存释放掉。接收缓冲区要复杂一些:上面三个数字单位都是字节,它们分别表示:(2)接收缓冲区的调整接收缓冲区可以根据系统空闲内存的大小来调节接收窗口:(3)内存的判断那么如何判断内存紧张或充分呢?上面三个数字单位不是字节,而是「页面大小」,1 页表示 4KB,它们分别表示:在实际的场景中,TCP 缓冲区最小值保持默认 4K 即可,来提高并发处理能力;最大值则尽可能靠近带宽时延积,来最大化网络效率。总结以上:为了提高并发能力、提高网络效率,我们要充分利用网络能力和自己的内存。网络这方面就是将缓冲区大小的极值尽可能靠近带宽时延积,而同时对缓冲区的自动调节需要结合内存来判断,这个 TCP 内存的判断是通过系统内存计算出来的几个值来划分的,在不同区间会对分配给缓冲区的内存大小进行调整。以上就是 TCP 在不同阶段的优化策略和思路,有关拥塞控制和流量控制之后再补一篇笔记。

试分析TCP/IP协议的体系结构和特点
1、TCP/IP体系结构TCP/IP协议实际上就是在物理网上的一组完整的网络协议。其中TCP是提供传输层服务,而IP则是提供网络层服务。TCP/IP包括以下协议:IP: 网间协议(Internet Protocol) 负责主机间数据的路由和网络上数据的存储。同时为ICMP,TCP,UDP提供分组发送服务。用户进程通常不需要涉及这一层。ARP: 地址解析协议(Address Resolution Protocol),此协议将网络地址映射到硬件地址。RARP: 反向地址解析协议(Reverse Address Resolution Protocol),此协议将硬件地址映射到网络地址。ICMP: 网间报文控制协议(Internet Control Message Protocol),此协议处理信关和主机的差错和传送控制。TCP: 传送控制协议(Transmission Control Protocol),这是一种提供给用户进程的可靠的全双工字节流面向连接的协议。它要为用户进程提供虚电路服务,并为数据可靠传输建立检查。(注:大多数网络用户程序使用TCP)UDP: 用户数据报协议(User Datagram Protocol),这是提供给用户进程的无连接协议,用于传送数据而不执行正确性检查。FTP: 文件传输协议(File Transfer Protocol),允许用户以文件操作的方式(文件的增、删、改、查、传送等)与另一主机相互通信。SMTP: 简单邮件传送协议(Simple Mail Transfer Protocol),SMTP协议为系统之间传送电子邮件。TELNET:终端协议(Telnet Terminal Procotol),允许用户以虚终端方式访问远程主机。HTTP: 超文本传输协议(Hypertext Transfer Procotol)。TFTP: 简单文件传输协议(Trivial File Transfer Protocol)。2、TCP/IP特点:TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现。因此用户一般不涉及。编程时,编程界面有两种形式:(1)是由内核心直接提供的系统调用;(2)使用以库函数方式提供的各种函数。前者为核内实现,后者为核外实现。用户服务要通过核外的应用程序才能实现,所以要使用套接字(socket)来实现。
(1)开放的协议标准,可以免费使用,并且独立于特定的计算机硬件与操作系统; (2)独立于特定的网络硬件,可以运行在局域网、广域网,更适用于互联网中; (3)统一的网络地址分配方案,使得整个TCP/IP设备在网中都具有惟一的地址; (4)标准化的高层协议,可以提供多种可靠的用户服务。

tcp主要功能
传输控制协议(TCP,Transmission Control Protocol)是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。 [2] 互联网络与单个网络有很大的不同,因为互联网络的不同部分可能有截然不同的拓扑结构、带宽、延迟、数据包大小和其他参数。TCP的设计目标是能够动态地适应互联网络的这些特性,而且具备面对各种故障时的健壮性。 [2]不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。 [3]应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。 [3]每台支持TCP的机器都有一个TCP传输实体。TCP实体可以是一个库过程、一个用户进程,或者内核的一部分。在所有这些情形下,它管理TCP流,以及与IP层之间的接口。TCP传输实体接受本地进程的用户数据流,将它们分割成不超过64KB(实际上去掉IP和TCP头,通常不超过1460数据字节)的分段,每个分段以单独的IP数据报形式发送。当包含TCP数据的数据报到达一台机器时,它们被递交给TCP传输实体,TCP传输实体重构出原始的字节流。为简化起见,我们有时候仅仅用“TCP”来代表TCP传输实体(一段软件)或者TCP协议(一组规则)。根据上下文语义你应该能很消楚地推断出其实际含义。例如,在“用户将数据交给TCP”这句话中,很显然这里指的是TCP传输实体。 [2] IP层并不保证数据报一定被正确地递交到接收方,也不指示数据报的发送速度有多快。正是TCP负责既要足够快地发送数据报,以便使用网络容量,但又不能引起网络拥塞:而且,TCP超时后,要重传没有递交的数据报。即使被正确递交的数据报,也可能存在错序的问题,这也是TCP的责任,它必须把接收到的数据报重新装配成正确的顺序。简而言之,TCP必须提供可靠性的良好性能,这正是大多数用户所期望的而IP又没有提供的功能。

TCP报文结构和功能简析
TCP:传输、控制、协议。TCP与UDP最大却别就在那个C上面,它充分实现了数据传输时各种控制功能。可以进行丢包重发控制,还可以对次序乱掉的数据包进行顺序控制,还能控制传输流量,这些是UDP中没有的。即T C P 提供一种面向连接的、可靠的字节流服务。TCP是一中面向有链接的协议,只有在确认对端存在的时候,才会发送分数据,从而也可以控制通信流量的浪费。什么是可靠的传输:不丢包、不损坏、不乱序、不重复。TCP通过校验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制来实现可靠传输。接收端查询就收数据TCP首部中的序号和数据长度。将自己下一步应该接受的序列号作为确认应答返送回去。就这样,通过序列号和确认应答,TCP实现可靠传输。一般使用TCP首部用于控制的字段来管理连接。一个连接的建立和断开,正常过程中,至少需要来回共7个包才能完成。TCP首部的数据结构如图所示:TCP包首部为了便于理解,忽略选项部分,固定首部通常为20个字节,将按作用分类分析。前4个字节来标识了发送方的端口号和接收方的端口号,即该数据包由谁发送,由谁接收。前2个字节标识源端口号,紧接着2个字节标识目的端口号。即发送方:(11111111,1111111)2= (65535)10,除去0~1023.即接收方:(11111111,1111111)2= (65535)10,除去0~1023.TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则是指的是本报文段所发送的数据的第一个字节的序号。长度为4字节,序号是32bit的无符号数,序号到达232- 1后又从0开始。ack:确认序号,即确认字节的序号,更确切地说,是发送确认的一端所期望收到的下一个序号。所谓的发送确认的一端就是将确认信息发出的一端。比如第二次握手的S端就是发送确认的一端。确认序号为上次接收的最后一个字节序号加1.只有确认标志位(ACK)为1的时候,确认序号才有效。也叫首部长度,占4个bit,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。TCP报文结构由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。“首部长度”是4位二进制数,单位是32位字,能表示的最大十进制数字是15。(1111)2=(15)10,即是15个32位,一个32位是4个字节,因此数据偏移的最大值是154=60个字节,这也是TCP首部的最大字节。因为固定首部的存在,数据偏移的值最小为20个字节,因此选项长度不能超过40字节*(减去20个字节的固定首部)。占6位,保留为今后使用,但目前应置为0。当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。当URG置为1时,应用进程就告诉TCP有紧急数据要传送。于是TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。仅当ACK = 1时确认号字段才有效,当ACK = 0时确认号无效。TCP规定,在连接建立后所有的传送的报文段都必须把ACK置为1。当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。发送方TCP把PSH置为1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程。而不用再等到整个缓存都填满了后再向上交付。当RST=1时,表明TCP连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。因此SYN=1就表示这是一个连接请求或连接接受报文。用来释放一个连接。当FIN=1时,表明此报文段的发送发的数据已发送完毕,并要求释放运输连接。占2字节。窗口值是(0,216-1)之间的整数。窗口指的是发送本报文段的一方的接受窗口(而不是自己的发送窗口),窗口大小是给对方用的。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方一次发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。例如,A发送了一个报文段,其确认号是3000,窗口字段是1000.这就是告诉对方B:“从3000算起,A接收缓存空间还可接受1000个字节数据,字节序号是3000-3999”,可以想象到河道的阀门。总之:窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化。占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式和UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6);把第5字段中的UDP中的长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用TPv6,则相应的伪首部也要改变。占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据) 。因此,在紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为0时也可以发送紧急数据。长度可变,最长可达40个字节。当没有使用“选项”时,TCP的首部长度是20字节。最大报文段长度(MSS:Maximum Segment Size)表示TCP传往另一端的最大块数据的长度。当一个连接建立时,连接的双方都要通告各自的MSS。当建立一个连接时,每一方都有用于通告它期望接收的MSS选项(MSS选项只能出现在SYN报文段中),如果一方不接收来自另一方的MSS值,则MSS就定为默认值536字节(这个默认值允许20字节的IP首部和20字节的TCP首部以适合576字节IP数据报) 。为什么要规定一个最大报文长度MSS呢?这并不是考虑接受方的接收缓存可能存放不下TCP报文段中的数据。实际上,MSS与接收窗口值没有关系。我们知道,TCP报文段的数据部分,至少要加上40字节的首部(TCP首部20字节和IP首部20字节,这里还没有考虑首部中的可选部分)才能组装成一个IP数据报。若选择较小的MSS长度,网络的利用率就降低。设想在极端情况下,当TCP报文段只含有1字节的数据时,在IP层传输的数据报的开销至少有40字节(包括TCP报文段的首部和IP数据报的首部)。这样,对网络的利用率就不会超过1/41。到了数据链路层还要加上一些开销。但反过来,若TCP报文段非常长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片组成成原来的TCP报文段,当传输出错时还要进行重传,这些也都会使开销增大。因此,MSS应尽可能大些,只要在IP层传输时不需要分片就行。由于IP数据报所经历的路径是动态变化的,因此在这条路径上确定的不需要的分片的MSS,如果改走另一条路径就可能需要进行分片。因此最佳的MSS是很难确定的。在连接过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传输数据,两个传送方向可以有不同的MSS值。若主机未填写这一项,则MSS的默认值是536字节长。因此,所有在互联网上的主机都应该接受的报文段长度是536+20(固定首部长度)=556字节。后来又增加了几个选项如窗口扩大选项、时间戳选项等。窗口扩大选项是为了扩大窗口。我们知道,TCP首部中窗口字段长度是16位,因此最大的窗口大小为64K字节。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,传播时延和宽带都很大,要获得高吞吐量需要更大的窗口大小。窗口扩大选项占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。移位值允许使用的最大值是14,相当于窗口最大值增大到2(16+14)-1=230-1。窗口扩大选项可以在双方初始建立TCP连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0选项,使窗口大小回到16。时间戳选项占10字节,其中最主要的字段是时间戳字段(4字节)和时间戳回送回答字段(4字节)。时间戳选项有以下两个概念:第一、 用来计算往返时间RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确地计算出RTT来。第二、 用于处理TCP序号超过232的情况,这又称为防止序号绕回PAWS。我们知道,TCP报文段的序号只有32位,而每增加232个序号就会重复使用原来用过的序号。当使用高速网络时,在一次TCP连接的数据传送中序号很可能被重复使用。例如,当使用1.5Mbit/s的速度发送报文段时,序号重复要6小时以上。但若用2.5Gbit/s的速率发送报文段,则不到14秒钟序号就会重复。为了使接收方能够把新的报文段和迟到很久的报文段区分开,则可以在报文段中加上这种时间戳。从功能和性能的角度去理解三次握手建立连接第一次:C向S发送一个建立连接的请求。此过程中携带一些报文属性信息,这些信息,存在于报文首部,有初始化用的信息,比如,有用于认证的信息。初始化信息:如报文序列号、SYN:TCP在数据通信之前,通过TCP首部发送的一个SYN标志位,作为建立连接的请求等待接收方确认应答。如果S发来确认应答,则认为可以进行数据通信,否则,就不能进行通信。TCP规定:****SYN=1的报文段不能携带数据,但是要消耗掉一个序号:seq=x。这个时候C进入SYN-SENT(同步已发送)状态。第二次:S收到C请求后,如果同意建立连接,则向C返回确认信息:将SYN、ACK都置1,确认号为ack=seq+1(seq来自客户端),并携带自己的初始化,同时用于认证的信息S。同理:SYN=1的报文段不能携带数据,但是要消耗掉一个序号:seq=y。这个时候S进入SYN-RCVD(同步已接收)状态。C收到S返回的确认信息后,进入ESTABLISHED(已建立连接)的状态,第三次:C收到S返回的确认信息后,向S再一次发送确认报文。ACK置为1,确认号ack=seq+1(seq来自S),自己的seq=x+1。TCP规定:ACK报文可以携带数据。但是,如果不携带数据,则不消耗序号,这时,下一数据报文段的序号仍是seq=x+1。服务器收到客户端返回的确认信息后,也进入ESTABLISHED(已建立连接)的状态,从功能角度去考虑前两次握手,从性能的角度去理解为什么需要第三次握手。有第三次,是考虑到一种错误情况:假设C发了一请求建立连接的报文,长时间未收到S的确认报文,则C会重发,这个时候S与之建立连接、完成数据通信、关闭了连接,这个时候C第一发出的请求建立连接的报文到达了S,S则会等待C发送数据,实际上C已经CLOSED了,S就一直在这等待,浪费资源,确切地说,应该是至少四次数据交互才能实现一个连接的彻底关闭。关闭连接,需要四个报文来指示关闭。TCP是全双工通信的,所以在一端发送数据完毕后,还具有接收另一端的数据的能力,这就所谓的半关闭。四次挥手举个例子:如果C的数据已经发送完毕,C是不能立即关闭的,因为建立连接的通信双方是平等的。C首先告诉S:“数据发送完毕“,这个消息在TCP报文的首部由FIN来标识,让S知道C是准备断开连接了。这是第一次挥手。S收到C发来的FIN标识的报文后,要给C端恢复一个确认FIN的消息,告诉C说,知道你的数据发完了。这是第二次挥手。这个时候,如果S端的数据也发送完毕了,就给C发一个FIN=1报文。这是第三次挥手。C收到S发来的FIN标识的报文后,要给S端恢复一个确认FIN的消息,告诉C说,知道你的数据发完了。这是第四次挥手。然后就彻底断开连接了。TCP的状态变迁图

本文由 在线网速测试 整理编辑,转载请注明出处。