TCP

✍ dations ◷ 2024-07-03 00:52:25 #TCP
传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能。用户数据报协议(UDP)是同一层内另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来透过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认信息(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失并进行重传。TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和。数据在TCP层称为流(Stream),数据分组称为分段(Segment)。作为比较,数据在IP层称为Datagram,数据分组称为分片(Fragment)。 UDP 中分组称为Message。TCP协议的运行可划分为三个阶段:连接创建(connection establishment)、数据传送(data transfer)和连接终止(connection termination)。操作系统将TCP连接抽象为套接字表示的本地端点(local end-point),作为编程接口给程序使用。在TCP连接的生命期内,本地端点要经历一系列的状态改变。TCP用三次握手(或称三路握手,three-way handshake)过程创建一个连接。在连接创建过程中,很多参数要被初始化,例如序号被初始化以保证按序传输和连接的强壮性。一对终端同时初始化一个它们之间的连接是可能的。但通常是由一端打开一个套接字(socket)然后监听来自另一方的连接,这就是通常所指的被动打开(passive open)。服务器端被被动打开以后,用户端就能开始创建主动打开(active open)。如果服务器端接到了客户端发的SYN后回了SYN-ACK后客户端掉线了,服务器端没有收到客户端回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。于是,服务器端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻倍,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s才知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才会断开这个连接。使用三个TCP参数来调整行为:tcp_synack_retries 减少重试次数;tcp_max_syn_backlog,增大SYN连接数;tcp_abort_on_overflow决定超出能力时的行为。主机收到一个TCP包时,用两端的IP地址与端口号来标识这个TCP包属于哪个session。使用一张表来存储所有的session,表中的每条称作Transmission Control Block(TCB),tcb结构的定义包括连接使用的源端口、目的端口、目的ip、序号、应答序号、对方窗口大小、己方窗口大小、tcp状态、tcp输入/输出队列、应用层输出队列、tcp的重传有关变量等。服务器端的连接数量是无限的,只受内存的限制。客户端的连接数量,过去由于在发送第一个SYN到服务器之前需要先分配一个随机空闲的端口,这限制了客户端IP地址的对外发出连接的数量上限。从Linux 4.2开始,有了socket选项IP_BIND_ADDRESS_NO_PORT,它通知Linux内核不保留usingbind使用端口号为0时内部使用的临时端口(ephemeral port),在connect时会自动选择端口以组成独一无二的四元组(同一个客户端端口可用于连接不同的服务器套接字;同一个服务器端口可用于接受不同客户端套接字的连接)。对于不能确认的包、接收但还没读取的数据,都会占用操作系统的资源。在TCP的数据传送状态,很多重要的机制保证了TCP的可靠性和强壮性。它们包括:使用序号,对收到的TCP报文段进行排序以及检测重复的数据;使用校验和检测报文段的错误,即无错传输;使用确认和计时器来检测和纠正丢包或延时;流控制(Flow control);拥塞控制(Congestion control);丢失包的重传。通常在每个TCP报文段中都有一对序号和确认号。TCP报文发送者称自己的字节流的编号为序号(sequence number),称接收到对方的字节流编号为确认号。TCP报文的接收者为了确保可靠性,在接收到一定数量的连续字节流后才发送确认。这是对TCP的一种扩展,称为选择确认(Selective Acknowledgement)。选择确认使得TCP接收者可以对乱序到达的数据块进行确认。每一个字节传输过后,SN号都会递增1。通过使用序号和确认号,TCP层可以把收到的报文段中的字节按正确的顺序交付给应用层。序号是32位的无符号数,在它增大到232-1时,便会回绕到0。对于初始化序列号(ISN)的选择是TCP中关键的一个操作,它可以确保强壮性和安全性。TCP协议使用序号标识每端发出的字节的顺序,从而另一端接收数据时可以重建顺序,无惧传输时的包的乱序交付(英语:packet reordering)或丢包。在发送第一个包时(SYN包),选择一个随机数作为序号的初值,以克制TCP序号预测攻击(英语:TCP sequence prediction attack).发送确认包(Acks),携带了接收到的对方发来的字节流的编号,称为确认号,以告诉对方已经成功接收的数据流的字节位置。Ack并不意味着数据已经交付了上层应用程序。可靠性通过发送方检测到丢失的传输数据并重传这些数据。包括超时重传(Retransmission timeout,RTO)与重复累计确认(duplicate cumulative acknowledgements,DupAcks)。如果一个包(不妨设它的序号是100,即该包始于第100字节)丢失,接收方就不能确认这个包及其以后的包,因为采用了累计ack。接收方在收到100以后的包时,发出对包含第99字节的包的确认。这种重复确认是包丢失的信号。发送方如果收到3次对同一个包的确认,就重传最后一个未被确认的包。阈值设为3被证实可以减少乱序包导致的无作用的重传(spurious retransmission)现象。 选择性确认(英语:selective acknowledgment)(SACK)的使用能明确反馈哪个包收到了,极大改善了TCP重传必要的包的能力。发送方使用一个保守估计的时间作为收到数据包的确认的超时上限。如果超过这个上限仍未收到确认包,发送方将重传这个数据包。每当发送方收到确认包后,会重置这个重传定时器。典型地,定时器的值设定为 smoothed RTT + max ( G , 4 × RTT variation ) {displaystyle {text{smoothed RTT}}+max(G,4times {text{RTT variation}})} 其中 G {displaystyle G} 是时钟粒度。 进一步,如果重传定时器被触发,仍然没有收到确认包,定时器的值将被设为前次值的二倍(直到特定阈值)。这可对抗 中间人攻击方式的拒绝服务攻击,这种攻击愚弄发送者重传很多次导致接受者被压垮。TCP的16位的校验和(checksum)的计算和检验过程如下:发送者将TCP报文段的头部和数据部分的和计算出来,再对其求反码(一的补码),就得到了校验和,然后将结果装入报文中传输。(这里用反码和的原因是这种方法的循环进位使校验和可以在16位、32位、64位等情况下的计算结果再叠加后相同)接收者在收到报文后再按相同的算法计算一次校验和。这里使用的反码使得接收者不用再将校验和字段保存起来后清零,而可以直接将报文段连同校验加总。如果计算结果是全部为一,那么就表示了报文的完整性和正确性。注意:TCP校验和也包括了96位的伪头部,其中有源地址、目的地址、协议以及TCP的长度。这可以避免报文被错误地路由。按现在的标准,TCP的校验和是一个比较脆弱的校验。出错概率高的数据链路层需要更高的能力来探测和纠正连接错误。TCP如果是在今天设计的,它很可能有一个32位的CRC校验来纠错,而不是使用校验和。但是通过在第二层使用通常的CRC校验或更完全一点的校验可以部分地弥补这种脆弱的校验。第二层是在TCP层和IP层之下的,比如PPP或以太网,它们使用了这些校验。但是这也并不意味着TCP的16位校验和是冗余的,对于因特网传输的观察,表明在受CRC校验保护的各跳之间,软件和硬件的错误通常也会在报文中引入错误,而端到端的TCP校验能够捕捉到大部分简单的错误。 这就是应用中的端到端原则。流量控制(英语:flow control (data))用来避免主机分组发送得过快而使接收方来不及完全收下,一般由接收方通告给发送方进行调控。TCP使用滑动窗口协议(英语:Sliding Window Protocol)实现流量控制。接收方在“接收窗口”域指出还可接收的字节数量。发送方在没有新的确认包的情况下至多发送“接收窗口”允许的字节数量。接收方可修改“接收窗口”的值。当接收方宣布接收窗口的值为0,发送方停止进一步发送数据,开始了“保持定时器”(persist timer),以避免因随后的修改接收窗口的数据包丢失使连接的双侧进入死锁,发送方无法发出数据直至收到接收方修改窗口的指示。当“保持定时器”到期时,TCP发送方尝试恢复发送一个小的ZWP包(Zero Window Probe),期待接收方回复一个带着新的接收窗口大小的确认包。一般ZWP包会设置成3次,如果3次过后还是0的话,有的TCP实现就会发RST把链接断了。如果接收方以很小的增量来处理到来的数据,它会发布一系列小的接收窗口。这被称作愚蠢窗口综合症,因为它在TCP的数据包中发送很少的一些字节,相对于TCP包头是很大的开销。解决这个问题,就要避免对小的window size做出响应,直到有足够大的window size再响应:拥塞控制是发送方根据网络的承载情况控制分组的发送量,以获取高性能又能避免拥塞崩溃(congestion collapse,网络性能下降几个数量级)。这在网络流之间产生近似最大最小公平(英语:max-min fairness)分配。发送方与接收方根据确认包或者包丢失的情况,以及定时器,估计网络拥塞情况,从而修改数据流的行为,这称为拥塞控制或网络拥塞避免。TCP的现代实现包含四种相互影响的拥塞控制算法:慢开始、拥塞避免、快速重传、快速恢复。此外,发送方采取“超时重传”(retransmission timeout,RTO),这是估计出来回通信延迟 (RTT) 以及RTT的方差。RFC793中定义的计算SRTT的经典算法:指数加权移动平均(Exponential weighted moving average)1987年,出现计算RTT的Karn算法(英语:Karn's Algorithm)或TCP时间戳(RFC 1323),最大特点是——忽略重传,不把重传的RTT做采样。但是,如果在某一时间,网络闪动,突然变慢了,产生了比较大的延时,这个延时导致要重传所有的包(因为之前的RTO很小),于是,因为重传的不算,所以,RTO就不会被更新,这是一个灾难。为此,Karn算法一发生重传,就对现有的RTO值翻倍。这就是的Exponential backoff。1988年,在RFC 6298中给出范·雅各布森算法取平均以获得平滑往返时延(Smoothed Round Trip Time,SRTT),作为最终的RTT估计值。这个算法在被用在今天的TCP协议中:S R T T = S R T T + α ∗ ( R T T − S R T T ) {displaystyle SRTT=SRTT+alpha *(RTT-SRTT)} D e v R T T = ( 1 − β ) ∗ D e v R T T + β ∗ | R T T − S R T T | {displaystyle DevRTT=(1-beta )*DevRTT+beta *leftvert RTT-SRTTrightvert } R T O = μ ∗ S R T T + ∂ ∗ D e v R T T {displaystyle RTO=mu *SRTT+partial *DevRTT}其中:DevRTT是Deviation RTT。在Linux下,α = 0.125,β = 0.25, μ = 1,∂= 4当前有很多TCP拥塞控制算法在研究中。最大分段大小 (MSS)是在单个分段中TCP愿意接受的数据的字节数最大值。MSS应当足够小以避免IP分片,它会导致丢包或过多的重传。在TCP连接创建时,双端在SYN报文中用MSS选项宣布各自的MSS,这是从双端各自直接相连的数据链路层的最大传输单元(MTU)的尺寸减去固定的IP首部和TCP首部长度。以太网MTU为1500字节, MSS值可达1460字节。使用IEEE 802.3的MTU为1492字节,MSS可达1452字节。如果目的IP地址为“非本地的”,MSS通常的默认值为536(这个默认值允许20字节的IP首部和20字节的TCP首部以适合576字节IP数据报)。此外,发送方可用传输路径MTU发现(英语:path MTU discovery)(RFC 1191)推导出从发送方到接收方的网络路径上的最小MTU,以此动态调整MSS以避免网络IP分片。MSS发布也被称作“MSS协商”(MSS negotiation)。严格讲,这并非是协商出来一个统一的MSS值,TCP允许连接两端使用各自不同的MSS值。 例如,这会发生在参与TCP连接的一台设备使用非常少的内存处理到来的TCP分组。最初采取累计确认的TCP协议在丢包时效率很低。例如,假设通过10个分组发出了1万个字节的数据。如果第一个分组丢失,在纯粹的累计确认协议下,接收方不能说它成功收到了1,000到9,999字节,但未收到包含0到999字节的第一个分组。因而,发送方可能必须重传所有1万个字节。为此,TCP采取了“选择确认”(selective acknowledgment,SACK)选项。RFC 2018对此定义为允许接收方确认它成功收到的分组的不连续的块,以及基础TCP确认的成功收到最后连续字节序号。这种确认可以指出SACK block,包含了已经成功收到的连续范围的开始与结束字节序号。在上述例子中,接收方可以发出SACK指出序号1000到9999,发送方因此知道只需重发第一个分组(字节 0 到 999)。TCP发送方会把乱序收包当作丢包,因此会重传乱序收到的包,导致连接的性能下降。重复SACK选项(duplicate-SACK option)是定义在RFC 2883中的SACK的一项扩展,可解决这一问题。接收方发出D-ACK指出没有丢包,接收方恢复到高传输率。D-SACK使用了SACK的第一个段来做标志,D-SACK旨在告诉发送端:收到了重复的数据,数据包没有丢,丢的是ACK包;或者“Fast Retransmit算法”触发的重传不是因为发出去的包丢了,也不是因为回应的ACK包丢了,而是因为网络延时导致的reordering。SACK选项并不是强制的。仅当双端都支持时才会被使用。TCP连接创建时会在TCP头中协商SACK细节。在 Linux下,可以通过tcp_sack参数打开SACK功能(Linux 2.4后默认打开)。Linux下的tcp_dsack参数用于开启D-SACK功能(Linux 2.4后默认打开)。选择确认也用于流控制传输协议 (SCTP).TCP窗口尺寸域控制数据包在2至65,535字节。RFC 1323定义的TCP窗口缩放选项(英语:TCP window scale option)用于把最大窗口尺寸从65,535字节扩大至1G字节。扩大窗口尺寸是TCP优化(英语:TCP tuning)的需要。窗口缩放选项尽在TCP三次握手时双端在SYN包中独立指出这个方向的缩放系数。该值是16比特窗口尺寸的向左位移数,从0 (表示不位移)至14。某些路由器或分组防火墙会重写窗口缩放选项,这可能导致不稳定的网络传输。RFC 1323定义了TCP时间戳,并不对应于系统时钟,使用随机值初始化。许多操作系统每毫秒增加一次时间戳;但RFC只规定tick应当成比例。有两个时间戳域:TCP时间戳用于“防止序列号回绕算法”(Protection Against Wrapped Sequence numbers,PAWS),细节见RFC 1323。PAWS用于接收窗口跨序号回绕边界。这种情形下一个包可能会重传以回答问题:“是否是第一个还是第二个4 GB的序号?”时间戳可以打破这一问题。另外,Eifel检测算法(RFC 3522)使用TCP时间戳确定如果重传发生是因为丢包还是简单乱序。最近统计表明时间戳的采用率停滞在~40%,这归因于Windows服务器从Windows Server 2008起降低了支持。.带外数据(英语:out-of-band data)(OOB)是指对紧急数据,中断或放弃排队中的数据流;接收方应立即处理紧急数据。完成后,TCP通知应用程序恢复流队列的正常处理。OOB并不影响网络,“紧急”仅影响远程端的处理。这一协议很少被实现。正常情况下,TCP等待200 ms以准备一个完整分组发出(纳格算法试图把小的信息组装为单一的包)。这产生了小的、但潜在很严重的延迟并在传递一个文件时不断重复延迟。例如,典型发送块是4 KB,典型的MSS是1460字节,在10 Mbit/s以太网上发出两个包,每个耗时约~1.2 ms,随后是剩余1176个字节的包,之后是197 ms停顿因为TCP等待装满缓冲区。对于telnet,每次用户击键的回应,如果有200 ms将会非常烦人。socket选项TCP_NODELAY能放弃默认的200 ms发送延迟。应用程序使用这个socket选项强制发出数据。RFC定义了PSH能立即发出比特。Berkeley套接字不能控制或指出这种情形,只能由协议栈控制。连接终止使用了四路握手过程(或称四次握手,four-way handshake),在这个过程中连接的每一侧都独立地被终止。当一个端点要停止它这一侧的连接,就向对侧发送FIN,对侧回复ACK表示确认。因此,拆掉一侧的连接过程需要一对FIN和ACK,分别由两侧端点发出。首先发出FIN的一侧,如果给对侧的FIN响应了ACK,那么就会超时等待2*MSL时间,然后关闭连接。在这段超时等待时间内,本地的端口不能被新连接使用;避免延时的包的到达与随后的新连接相混淆。RFC793定义了MSL为2分钟,Linux设置成了30s。参数tcp_max_tw_buckets控制并发的TIME_WAIT的数量,默认值是180000,如果超限,那么,系统会把多的TIME_WAIT状态的连接给destory掉,然后在日志里打一个警告(如:time wait bucket table overflow)连接可以工作在TCP半开(英语:TCP half-open)状态。即一侧关闭了连接,不再发送数据;但另一侧没有关闭连接,仍可以发送数据。已关闭的一侧仍然应接收数据,直至对侧也关闭了连接。也可以通过测三次握手关闭连接。主机A发出FIN,主机B回复FIN & ACK,然后主机A回复ACK.一些主机(如Linux或HP-UX)的TCP栈能实现半双工关闭序列。这种主机如果主动关闭一个连接但还没有读完从这个连接已经收到的数据,该主机发送RST代替FIN。这使得一个TCP应用程序能确认远程应用程序已经读了所有已发送数据,并等待远程侧发出的FIN。但是远程的TCP栈不能区分Connection Aborting RST与Data Loss RST,两种原因都会导致远程的TCP栈失去所有的收到数据。一些应用协议使用TCP open/close handshaking,因为应用协议的TCP open/close handshaking可以发现主动关闭的RST问题。例如:TCP/IP栈采用上述方法不能保证所有数据到达对侧,如果未读数据已经到达对侧。下表为TCP状态码列表,以S指代服务器,C指代客户端,S&C表示两者,S/C表示两者之一:TCP使用了通信端口(Port number)的概念来标识发送方和接收方的应用层。对每个TCP连接的一端都有一个相关的16位的无符号端口号分配给它们。端口被分为三类:众所周知的、注册的和动态/私有的。众所周知的端口号是由因特网赋号管理局(IANA)来分配的,并且通常被用于系统一级或根进程。众所周知的应用程序作为服务器程序来运行,并被动地侦听经常使用这些端口的连接。例如:FTP、TELNET、SMTP、HTTP、IMAP、POP3等。注册的端口号通常被用来作为终端用户连接服务器时短暂地使用的源端口号,但它们也可以用来标识已被第三方注册了的、被命名的服务。动态/私有的端口号在任何特定的TCP连接外不具有任何意义。可能的、被正式承认的端口号有65535个。TCP是一个复杂的但同时又是在发展之中的协议。尽管许多重要的改进被提出和实施,发表于1981年的RFC793中说明的TCP(TCP-Tahoe)的许多基本操作还是未作多大改动。RFC1122:《因特网对主机的要求》阐明了许多TCP协议的实现要求。RFC2581:《TCP的拥塞控制》是一篇近年来关于TCP的很重要的RFC,描述了更新后的避免过度拥塞的算法。写于2001年的RFC3168描述了对明显拥塞的报告,这是一种拥塞避免的信号量机制。在21世纪早期,在所有因特网的数据包中,通常有大约95%的包使用了TCP协议。常见的使用TCP的应用层有HTTP/HTTPS(万维网协议),SMTP/POP3/IMAP(电子邮件协议)以及FTP(文件传输协议)。这些协议在今天被广泛地使用,这证明了它们的原作者的创造是卓越的。最近,一个新协议已经被加州理工学院的科研人员开发出来,命名为FAST TCP(基于快速活动队列管理的规模可变的传输控制协议)。它使用排队延迟作为拥塞控制信号;但是因为端到端的延迟通常不仅仅包括排队延迟,所以FAST TCP(或更一般地,所有基于排队延迟的算法)在实际互联网中的能否工作仍然是一个没有解决的问题。TCP并不是对所有的应用都适合,一些新的带有一些内在的脆弱性的运输层协议也被设计出来。比如,实时应用并不需要甚至无法忍受TCP的可靠传输机制。在这种类型的应用中,通常允许一些丢包、出错或拥塞,而不是去校正它们。例如通常不使用TCP的应用有:流媒体、实时多媒体播放器和游戏、IP电话(VoIP)等等。任何不是很需要可靠性或者是想将功能减到最少的应用可以避免使用TCP。在很多情况下,当只需要多路复用应用服务时,用户数据报协议(UDP)可以代替TCP为应用提供服务。

相关

  • 遗传漂变遗传漂变,或基因漂变(genetic drift),是指种群中基因库在代际发生随机改变的一种现象。由于任何一个个体的生存与繁殖都受到随机因素影响,繁殖过程可看做一种抽样,子代携带的等位
  • 众议院多数党(232)少数党(199)空缺(4)美利坚合众国众议院(英语:United States House of Representatives)为美国国会两院之一,另一院为参议院(上议院)。众议院是美国的下议院,美国各州在众议院
  • 利帕里岛利帕里(意大利语:Lìpari)是意大利墨西拿省的一个市镇,位于西西里岛北侧第勒尼安海中的伊奥利亚群岛。这个火山群岛最大的岛屿(介于维苏威火山和埃特纳火山之间,距西西里岛30公里),
  • 山口俊一山口俊一(1950年2月28日-),日本政治家,自由民主党党员。出身于德岛县三好郡池田町(现三好市)。1990年至今连续当选9届众议院议员。在自民党内属于为公会(麻生派)。现任内阁府特命担当
  • span class=chemf style=white-space:nowrap;Csub13/sub十三烷(分子式:C13H28),烷烃的一种,在室温下是无色可燃的液体。它是一些昆虫用于御敌时喷射出的化学物质成分。十三烷有802个同分异构体。健康危害: 吸入、摄入或经皮肤吸收后对身
  • 彩虹色彩虹色或虹彩(英语:Iridescence),是一种结构色。彩虹色常见于肥皂泡、蝴蝶翅膀、贝壳等物体。如果观测物体表面的角度改变,色彩也随之改变,这样一种光学现象就叫做虹彩现象,即彩虹
  • 已测序的生物已测序的生物指其基因组已经被完全测序的生物。其中部分生物的DNA序列已经被完全注释,功能性的片段(如基因等)已作图。借助于基因组研究及高通量处理等技术,越来越多的生物的全
  • 三磷酸胞苷三磷酸胞苷(英语:cytidine triphosphate, CTP)是一种核苷酸,为合成RNA的原料之一。CTP与ATP同为高能分子,但与ATP相较之下较少作为能量来源。CTP可参与甘油磷脂(例如磷脂酰胆碱和
  • 刘 明刘明(1964年4月-),生于江西丰城,籍贯安徽宿州,中国微电子科学与技术专家,中国科学院微电子研究所研究员。2017年当选为中国科学院院士。1964年生于江西丰城,籍贯安徽宿州,1985年毕业
  • 消遣功能休闲活动(英语:recreation),又称康乐或消遣,一种在余暇时进行的活动。通常进行消遣的动机是为了自己的快乐,而不是为了工作或一些正式的理由。在闲暇时会寻找消遣活动,被认为是一种