现在的操作系统基本都实现了TCP/IP协议,TCP/IP协议栈分为五层:
应用层:向用户提供的一组常用的应用程序,如TELNET,FTP,SMTP,SNTP,DNS,HTTP,这些应用程序有一个端口用来标识。
传输层:主要协议是TCP和UDP,提供应用程序的通信。
网络层:主要协议是IP协议,定义了IP地址格式,是不同应用程序的数据在网络上通畅传输的关键。
链路层:这是TCP/IP软件的最低层,负责接收IP数据包并通过网络发送之,或者从网络上接收物理帧,抽出IP数据报,交给IP层。
物理层:
每层都有不同的协议,这些协议其实就是双方进行通信的一种格式。在此我们分析TCP/UDP/IP协议。
在网络中,一帧以太网数据包的格式如下:
1、TCP协议
TCP协议是面向连接、保证高可靠性(数据无丢失,无失序,无错误,无重复)的传输协议。这里就不再详解TCP报头了。在TCP传输中,重点要了解三次握手建立连接和四次挥手释放连接的过程,这在我的socket通信博文中详细的解释。
TCP是如何保证可靠性传输的呢?在TCP中采用一种名为“带重传功能的肯定确认”机制作为提供可靠数据传输服务的基础。这项技术要求接收方收到数据之后向源站回送确认信息ACK。发送方对发出的每个分组都保存一份记录,在发送下一个分组之前等待确认信息。发送方还在送出分组的同时启动一个定时器,并在定时器的定时期满而确认信息还没有到达的情况下,重发刚才发出的分组。如下图,左边是正常传输的情况,右边是出现分组丢失的情况,当发送方在正常时间内还没有收到接收方发送来的确认消息,则启动定时器,定时器超时后重传分组。
可是网络传输过程中是不可预测的,比如由于拥塞导致延迟,为了避免由于网络延迟引起迟到的确认和重复的确认,协议规定在确认信息中稍带一个分组的序号,使接收方能正确将分组与确认关联起来。从图 3-5可以看出,虽然网络具有同时进行双向通信的能力,但由于在接到前一个分组的确认信息之前必须推迟下一个分组的发送,简单的肯定确认协议浪费了大量宝贵的网络带宽。为此, TCP使用滑动窗口的机制来提高网络吞吐量,同时解决端到端的流量控制。滑动窗口技术因此而产生了。
滑动窗口技术是简单的带重传的肯定确认机制的一个更复杂的变形,它允许发送方在等待一个确认信息之前可以发送多个分组。如图 3-7所示,发送方要发送一个分组序列,滑动窗口协议在分组序列中放置一个固定长度的窗口,然后将窗口内的所有分组都发送出去;当发送方收到对窗口内第一个分组的确认信息时,它可以向后滑动并发送下一个分组;随着确认的不断到达,窗口也在不断的向后滑动。
2、UDP协议
UDP协议与TCP协议都处于第四层——传输层,但与TCP协议不同,它是一种无连接、不可靠的传输协议,它不提供数据包分组、组装,也不对数据包排序,报文发送之后,无法得知其是否安全完整到达。因此选择UDP必须谨慎,在网络质量特别差的时候,数据包丢包情况会比较严重。既然如此,那我们为什么还需要使用UDP协议呢?这得说下UDP的特性了:
(1)由于传输数据不建立连接,不需要维护连接状态和收发状态了,因此一台服务机可同时向多个客户机传输相同的消息。
(2) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
正是UDP具有资源消耗小,处理速度快的特点,在一些视频、音频和普通数据传输中使用较多,比如QQ,SNMP,DNS等,因为他们即使偶尔丢失一两个数据包并不会对接收结果产生影响。
UDP和TCP都是使用端口号来标识运行在某个设备上的应用程序。IETF IANA定义了三种端口组:公认端口(0-1023)、注册端口(1024-49151)和动态/私有端口(49152-65535)。
数据传输过程举例:
接收数据的主机A的应用程序要申请一个UDP端口,假设为P,发送方应用程序准备好数据后,将其交给UDP协议,让其将该数据发送给主机A的端口P。UDP协议将应用程序的数据作为UDP数据包的数据部分封装在一个UDP数据包中。将数据包的目标端口字段设置为P。然后将UDP数据包交给IP协议处理,IP协议将UDP数据包作为IP数据包的数据封装在一个IP数据包里,将目的地址设为A,协议字段设置为17,然后交到网络层处理并发送出去。可能经过几次路由,最终到达主机A的IP协议层。主机A的IP协议发现协议字段为17,就将IP数据包的数据区提取出来交给UDP协议处理。UDP根据端口号P,将数据区放置在UDP端口P的队列中,A的应用程序就从该队列中将数据取出,进行处理。
3、IP协议
IP是TCP/IP协议族中最为核心的协议。所有的TCP、UDP、ICMP及IGM P数据都以IP数据报格式传输,它的特点如下:
不可靠(unreliable):意思是它不能保证IP数据报能成功地到达目的地。IP仅提供最好的传输服务。如果发生某种错误时,如某个路由器暂时用完了缓冲区, IP有一个简单的错误处理算法:丢弃该数据报,然后发送 ICMP消息报给信源端。任何要求的可靠性必须由上层来提供(如TCP) 。
无连接(connectionless):这个术语的意思是IP并不维护任何关于后续数据报的状态信息。每个数据报的处理是相互独立的。这也说明,IP数据报可以不按发送顺序接收。如果一信源向相同的信宿发送两个连续的数据报(先是A,然后是B) ,每个数据报都是独立地进行路由选择,可能选择不同的路线,因此B可能在A到达之前先到达。
在这里不得不说下分片技术了。
以太网和802.3对数据帧的长度都有一个限制,其最大值分别是1500和1492个字节,链路层的这个特性称作MTU。不同类型的网络大多数都有一个上限。如果IP层有一个数据要传,且数据的长度比链路层的MTU还大,那么IP层就要进行分片(fragmentation),把数据报分成若干片,这样每一个分片都小于MTU。
把一份IP数据报进行分片后,由到达目的端的IP层来重组,这个过程对上层传输层是透明的。由于每一分片都是一个独立的包,当这些数据报的片到达目的端时有可能会失序,但是在IP首部中有足够的信息让接收端能正确组装这些数据报片。
尽管如此,但依然有让人不如意的地方:那就是即使只丢失一片数据也要重传整个数据报。why?因为IP层本身没有超时重传机制------由更高层(比如TCP)来负责超时和重传。当来自TCP报文段的某一片丢失后,TCP在超时后会重发整个TCP报文段,该报文段对应于一份IP数据报(而不是一个分片),没有办法只重传数据报中的一个数据分片。
使用UDP很容易导致IP分片,TCP试图避免IP分片。那么TCP是如何试图避免IP分片的呢?其实说白了,采用TCP协议进行数据传输是不会造成IP分片的,因为一旦TCP数据过大,超过了MSS,则在传输层会对TCP包进行分段(如何分,见下文!),自然到了IP层的数据报肯定不会超过MTU,当然也就不用分片了。而对于UDP数据报,如果UDP组成的IP数据报长度超过了1500,那么IP数据报显然就要进行分片,因为UDP不能像TCP一样自己进行分段。总结:UDP不会分段,就由我IP来分。TCP会分段,当然也就不用我IP来分了!
MSS(Maxitum Segment Size)最大分段大小的缩写,是TCP协议里面的一个概念:
(1)MSS就是TCP数据包每次能够传输的最大数据分段。为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以往往MSS为1460。通讯双方会根据双方提供的MSS值得最小值确定为这次连接的最大MSS值。
(2)相信看到这里,还有最后一个问题:TCP是如何实现分段的呢?其实TCP无所谓分段,因为每个TCP数据报在组成前其大小就已经被MSS限制了,所以TCP数据报的长度是不可能大于MSS的,当然由它形成的IP包的长度也就不会大于MTU,自然也就不用IP分片了。