TCP的多路复用和分解
第一层:物理层
第二层:数据链路层 802.2、802.3ATM、HDLC、FRAME RELAY
第三层:网络层 IP、IPX、APPLETALK、ICMP
第四层:传输层 TCP、UDP、SPX
第五层:会话层 RPC、SQL、NFS 、X WINDOWS、ASP
第六层:表示层 ASCLL、PICT、TIFF、JPEG、 MIDI、MPEG
第七层:应用层 HTTP,FTP,SNMP等
将运输层报文段中的数据交付到正确的套接字的工作称为多路分解(demultiplexing),在源主机当中从不同的套接字中收集数据块,并为每一个数据块封装上首部信息(用于分解)从而生成报文段,然后将此报文段传递到网络层。所有的这些工作称为多路复用(multiplexing)。
运输层多路复用的要求:
- 套接字有唯一的标识符;
- 每一个报文段有特殊的字段来指示该报文段所要交付到的套接字。(这些特殊的字段是源端口字段和目的端口字段,端口号是一个16bit的数范围是0-65535.其中0-1023是周知端口)。
TCP的首部开销为20个字节,而UDP的首部开销为8字节
无连接的多路复用与多路分解(UDP)
-
一个UDP套接字是由一个二元组来全面标志的,该二元组包含一个目的IP地址和一个目的端口号,因此如果两个UDP报文段有不同的源IP地址和/或源端口号,但是具有相同的目的IP地址和目的端口号,那么这两个报文段将通过相同的套接字被定向到相同的进程
UDP报文格式
- 长度字段:指示了在UDP报文段中的字节数(首部加数据,以字节为单位)
- 检验和:接收方使用检验和来检查在该报文段中是否出现差错
UDP虽然实现了检验和,但是对恢复差错无能为力,要么它丢弃受损的报文段,要么将受损的报文段交给应用程序并给出警告。
- UDP可以是一对一、一对多、多对一、多对多的。
面向连接的多路复用和多路分解(TCP)
- TCP套接字和UDP套接字的细微的差别是,TCP套接字是由一个四元组(源IP地址,源端口号,目的IP地址,目的端口号)来标识的。这样当一个TCP报文段从网络到达另外一台主机时,该主机使用全部的4个值来将报文段定向(分解)到相应的套接字。特别与UDP不同的是,两个具有不同的IP地址的或者是源端口号的到达TCP报文段将被定向到两个不同的套接字,除非TCP报文段携带了初始创建连接的请求 。服务器主机可以支持很多并行的TCP套接字,每一个套接字和一个进程相联系,并由其四元组来标识每一个套接字。当一个TCP报文段到达主机时,所有的四个字段(源IP、源端口、目的IP、目的端口)被用来将报文段定向(分解)到相应的套接字。
- TCP连接总是点对点的,所谓的“多播”,即在一次的发送操作当中从一个发送方将数据传输给多个接收方,对于TCP来说是不可能的。
TCP报文格式
- 32位序号: 32位的序列号由接收端计算机使用,重组分段的报文成最初的形式,当SYN出现,序列码实际上是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1。这个序列号(序列码)可以用来补偿传输中的不一致。
- 32位确认序号:32位的序列号由接收端计算机使用,重组分段的报文成最初的形式,如果设置了ACK控制位,这个值表示一个准备接收的包的序列码。
假设主机A已经接收到了一个来自主机B的包含字节0 ~ 355的报文段,以及另外的一个包含字节900~1000的报文段,由于某种原因,主机A还没有收到字节536 ~ 899的报文段,因此主机A为了重构主机B的数据流,仍然在等待536和其后的字节,于是A到B的下一个报文段将在确认号中包含536。因为TCP只确认该流中至第一个丢失字节为止的字节,所以TCP被称为提供累计确认。
- 4位首部长度:指示TCP头部大小(以32bit为单位),指示何处数据开始,由于TCP选项的原因,TCP首部长度是可变的。(但是通常选项为空,TCP头部典型长度为20字节,所以首部长度通常为5,即1001).
- 16位窗口大小:用来表示想要收到的每个TCP数据段的大小。TCP的流量控制由连接的每一端通过声明窗口的大小来提供。窗口的大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收到的字节。窗口的大小是一个16字节字段,因而窗口大小最大为65535字节。
- 16位检验和:16位TCP头部检验和。源主机基于数据内容计算一个数值,目的主机要和源主机计算的结果一致,从而验证数据的有效性。检验和覆盖的是整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证。
URG:紧急标志,为1时表示有效,紧急数据的最后一个字节由16bit的紧急数据指针字段指出。当紧急数据存在时,
ACK:确认标志。表明确认编号栏有效,大多数情况下该标识位是置位的。TCP报头内的确认编号栏内包含的确认编号(W+1)为下一个预期接收到的序列编号,同时提示远端系统已经成功的接收到了所有数据。
PSH:推标志。该标志置位时,接收端不将该数据进行队列处理,而是尽可能快地将数据转由应用处理(接收方立即将数据交给上层)。在处理Telnet或rlogin等交互模式的连接时,该标志总是置位的。
RST:复位标志。用于复位(重置)相应的TCP连接。
SYN:同步标志。表明同步序列编号栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。
FIN:结束标志。
TCP三次握手建立连接
-
三次握手(Three-Way Handshake)即建立TCP连接时,需要客户端和服务端总共发送3个包确认连接的建立。在socket编程中,这一过程由客户端执行connect()来触发。流程如下:
TCP三次握手
- 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
- 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
- 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。(前两次握手是是不承载"有效载荷"的,而第三次握手是可以承载"有效载荷"的。)
其中有一个半连接状态:服务器维护一个半连接队列,该队列为每个客户端SYN包开设一个条目,标明服务器已经接到SYN包,并向客户端发出确认,这些条目表示的连接处于SYN_RECV状态,得到客户端的确认后进入ESTABLISHED状态。
TCP采用三次握手是为了防止失效的连接请求报文段突然又传送到了主机B,因而产生错误,失效的连接请求报文段是指:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机A第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直在等待主机A发送数据,导致主机B的资源浪费。基于上述原因,采用两次握手是不可行的。
SYN攻击:
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:#netstat -nap | grep SYN_RECV
TCP四次挥手断开连接
-
四次挥手(Four-Way Wavehand)是指断开一个TCP连接时需要客户端和服务器总共发送四个包以确认连接的断开。在socket()编程中,这一个过程由客户端或者服务器端的任意一方执行close来触发。整个流程图如下:
TCP四次挥手
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。
- 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
- 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
- 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
- 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
假设客户端应用程序决定要关闭TCP连接,这引起客户TCP发送一个带有FIN比特被置为1的TCP报文段,并进入FIN_WAIT_1状态。当处于这个状态时,客户TCP等待一个来自服务器的带有确认的TCP报文段,当它收到该报文段时,客户TCP进入FIN_WAIT_2状态。当处于这一状态时,客户等待来自服务器的FIN比特被置为1的另外一个报文段;当收到该报文段后,客户TCP对服务器的报文段进行确认,并进入TIME_WAIT状态。假定ACK丢失,TIME_WAIT状态使TCP客户重传最后的确认报文。经过等待以后,连接就正式关闭,客户端的所有资源将会被释放。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
原因有二:
一、保证TCP协议的全双工连接能够可靠关闭
二、保证这次连接的重复数据段从网络中消失
先说第一点,如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
再说第二点,如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
往返时间的估计和超时
- TCP采用的是超时/重传机制来处理报文段的丢失,TCP中的超时间隔必须要大于该连接的往返时延(RTT:Round Trip Time).
可靠的数据传输
- TCP在IP不可靠的尽力而为的服务之上创建了一中可靠数据传输服务。TCP的可靠数据传输服务确保一个进程从其接收缓存中读出的数据流是无损坏的、无间隔、非冗余、按序的数据流。即该字节流与连接的另一端发出的字节流是完全一样的。
TCP的流量控制
- 一条TCP连接每一侧的主机都为该连接设置了接收缓存,当该TCP连接收到正确的,按序到达的字节以后,他就将数据放入到接收缓存,相关联的应用进程会从该缓存中读取数据,但不必是数据刚一到达就读取,从而导致缓存变小。为了防止接收方因缓存溢出而丢失数据,因此需要匹配双方的速率.
TCP通过让发送方维护一个被称为接收窗口的变量来提供流量控制
TCP的拥塞控制
TCP必须使用端到端的拥塞控制而不是使用网络辅助的拥塞控制,因为IP层不向端系统提供显示的网络拥塞反馈。TCP让每一个发送方根据所感知到的网络拥塞程度来限制他能向连接发送流量的速率。运行在发送方的TCP拥塞控制机制跟踪一个额外的变量拥塞窗口,拥塞窗口对一个TCP发送方能向网络中发送流量的速率进行了限制。在一个发送方中未被确认的数据量不会超过拥塞窗口和发送窗口中的最小值
- 通常的拥塞控制算法有:
- 慢启动
- 拥塞避免
- 快速恢复