技术干货丨TCP/IP漫游(上)

2017/01/18 10:41
阅读数 297

文丨Robbie_22 转载自:http://blog.mrriddler.com/

TCP/IP是互联网的基础协议栈,它包括大大小小几十个协议。本篇文章主要涉及到就是HTTP、TCP、IP协议。我们经常学的网络模型是七层或者五层,实际上一般认为一共只有四层就可以了。

Application layer ->HTTP

Transport layer                          ->TCP

Internet layer                             ->IP

 Link layer                                  ->Ethernet

应用层、传输层、网际层、连接层,这一眼看上去,很直白嘛,就是分层抽象,层与层互相隔离,这确实没问题。不过,我们可以换个角度来整体理解一下这四层。网络所做的就是传输数据嘛,那这四层就是数据在不同阶段的不同形式。应用层是数据的最终形式,传输层是数据的字节形式,网际层是数据的二进制形式,连接层是数据的信号形式。这样换一个角度去看世界也是蛮有意思的,并且这么看四层就更像是一个整体了。

数据在发送通过这四层的时候,每经过一层会将数据作为Body,并加上这一层的控制信息作为header。而到达目的地后,再这通过四层时,每层会将相应的header剥离,最后给接收方一个与发送方发送的一模一样的数据。

HTTP

HTTP已有很多文章介绍了,这篇文章就不多说了。仅聊一聊对HTTP协议的理解,HTTP协议内部实际上是一个,协议字符串解析器。HTTP协议以字符串形式将数据解析、逆解析成请求行/响应行、请求头、请求体构成的报文。为什么说是字符串解析器呢?实际上,请求行、响应行、header甚至是分隔标识(CRLF)都是字符串。而body就是数据,并且HTTP将数据的最终形式交由协议使用者来决定(text、xml、json等)。

TCP

你需要知道的关于TCP的第一件事就是TCP是个包含非常多知识点的协议(⊙﹏⊙),并且它还是一个实践性很强的协议,TCP中很多为什么这么做,都是应用于网络中实践出真知得出的“真理”。TCP是个可靠传输协议,在如此动荡(不安)的网络环境里,想要确保这一点可不容易,TCP独有很多机制来做到这一点。先来聊一下可靠传输协议。

可靠传输协议要求,双方的报文段(segment)必须都能无损的到达,并且发送方和接收方最后的报文段顺序需要一致。这代表,要检查报文是否完好无损,完好无损才算个合格的报文。如果报文受损或者发送方报文段根本没有到达接收方,发送方需要重传。如何知道报文根本没有到达接收方?发送方启动一个计时器就可以,计时器超时就认为报文没有到达接收方。

并且既然重传就需要接收方要对发送方确认,确认后发送方才放心。最简单的确认做法就是,一方发送报文段,另一方再发送一个单独做确认的报文段,但这样太低效了。不如,在发送自己的报文段的时候,顺便确认下所接受的报文段。为了最后要确认顺序,报文段还需要有序号来标识顺序。而上面说的这个几点在TCP协议中都有体现,更直接的在TCP header中就有体现。

TCP还是一个面向连接的协议,建立连接是通过大名鼎鼎的三次握手,断开连接通过四次挥手。这个连接肯定不是建立物理上的连接,而是逻辑上建立了连接。连接也就指的是,发送方和接收方都要初始化一些状态会被用来跟踪(track)发送过程,也就说TCP是个有状态的协议,三次握手和四次挥手后面会聊。

TCP提供端到端的服务,它会具体到应用程序的port。不同于IP提供点到点的服务,如果将发送数据比作送快递的话,IP提供的服务就是,快递员准确的送到你家,TCP提供的服务就是,不仅送到你家,还将快递准确的交到接收人的手上。

TCP除了要做到可靠传输,并且还要照顾接收方和网络总体状况,这其中还有流量控制和拥塞控制。上面说的这些机制后文会一个一个聊,现在先来看一下TCP的header。

TCP Header

输入图片说明

我们来逐一的过一下这些字段,Source Port和Destination Port代表目的和源端口。

Sequence Number代表报文段的序号来表示顺序。Acknowledgment Number代表发送方作为接收方已接收的报文段,并且期望收到下个报文段的开始序列号。TCP实际上将传送数据看做成数据的字节流,而不是一个个单独的报文段。这点从Sequence Number就可以看出,Sequence Number以传送的字节数作为单位,而不以报文段的数量作为单位。

Data Offset作为对齐的空位,Reserved作为保留位。下面是重点Flag位。

Flag包括Urgent、Ack、Push、Reset、Syn、Fin这6位。Urgent作为报文段的紧急数据标识,但具体如何处理交给接收方决定。Reset作为报文段的连接异常结束或端口号错误的标识。而Ack确认、Syn同步、Fin结束在三次握手和四次挥手中作为关键标识位。Push代表TCP不再等待是否还有其他报文段到达,马上交给上层应用层。

Window位作为流量控制的基础,后面会更具体的聊。

Check Sum作为校验位,校验报文段是否在传输过程中受损。Urgent Pointer在Urgent位为1时,才会出现,指向紧急数据的最后一个字节。

Options常见的标识有nop、TS val(time stamp)、ecr(echo reply)、mss。nop标识就和气泡指令一个意思,就是占位的。而TS val和ecr分别代表发送方的时间戳和接收方的时间戳,基于这两个时间戳来计算出RTT往返时间 (round-trip time) ,当然还要加权平均,具体计算就不多说了,RTT会被用来衡量重传计时器的超时时长。mss(Maximum Segment Size)指的是,连接层每次传输的数据有个最大限制MTU(Maximum Transmission Unit),一般是1500比特,超过这个量要分成多个报文段,mss则是这个最大限制减去TCP的header,光是要传输的数据的大小,一般为1460比特。

三次握手

三次握手,只能由客户端向服务端发起。第一次客户端发送SYN为1,序列号seq为某序列号,表示客户端想要建立连接。第二次服务端返回ACK、SYN都为1,序列号seq为某序列号,确认号为接收的序列号加1,表示确认服务端也想要建立连接。第三次客户端发送ACK为1,确认号为所接收序列号加1,再次确认,然后连接建立。

为何要进行三次握手?为了防止失效的报文段又到达了服务端产生错误。假设,客户端发送的第一个报文段延时到达了服务端,这个报文应被认为失效。但服务端误认为客户端想要建立一个新连接,就发出了确认,若没有第三次确认再建立起连接。服务端就错误地建立起一个连接。

如果三次握手,第三次失败了会怎么办?此时,服务端并不会马上放弃,服务端还会尝试重新发送确认,默认重试5次,间隔从1秒开始,后来每次是前一次的2倍。5次重试后,未果则放弃连接。

四次挥手

四次挥手,客户端和服务端都可以发起。第一次发送方发送FIN为1、ACK为1,序列号为某序列号,表示发送方想结束连接。第二次接收方发送ACK为1,确认号为接收序列号加1,表示我还没有准备好结束连接。第三次接收方发送FIN为1、ACK为1,序列号为某序列号,表示我已经准备好结束连接了。第四次发送方,发送ACK为1,确认号为所接收序列号加1,表示确认,结束连接。

半关闭

在四次挥手的基础上,发送方可以在接收第二次接收方发送ACK后,可以形成发送方不再发送报文段,但仍然接收接收方发送的报文段的这种现象。这就形成了半关闭。

一开始,我对TCP/IP一点都不感冒,这确实是自己懒。光看书和概念,味如嚼蜡。还是动手实验,才会有更深的体会,推荐tcpdump工具。tcpdump如何使用点我。下面是我用tcpdump截的几个报文段。

tcpdump第一行截到的信息翻译:

实际上,图中的五个报文段,其中的三个报文段正是TCP三次握手的过程。读者可以尝试找一下哪三个是。

这里还有一张TCP四次挥手的截图:

TCP的确认方式

实际上,TCP实现的可靠传输协议还有更多的细节。上文说道可靠协议在发送自己的报文段的时候,可以顺便确认下所接受的报文段。TCP就是这样去确认,以至于TCP确认会延迟,去等待是否有报文段发送,让报文段捎上确认。延迟一般为200毫秒。

比如说TCP使用的确认方式。TCP使用了累计确认。接收方为了交付给应用层正确的顺序,只有顺序正确的报文段会被确认然后交付给上层。发送方如果收到了接收方的某个确认号,即使这个确认号以前的报文段没有收到确认号也会被认为正确接收。

TCP还会使用选择确认(selective acknowledgement)。假设,发送方发送了多个报文段,初始的报文段出现了问题,没有抵达接收方。发送方会仅仅认为这个初始的报文段失效了,而后发送的几个报文段准确到达了接收方。也就是说,后发送的报文段虽然没有接收到直接的确认,而发送方选择性的确认了他们。接收方会将后发送的失序报文段先放入缓冲(buffer)中。这就是TCP实践出真知的最好例子。网络环境动荡一般会影响单个报文段,而不会影响一大片的报文段。

基于上面所说的累计确认和选择确认,若是报文段失效,发送可能会收到多次对于同一个报文段的冗余确认,若是收到了三次冗余确认,就认为这个报文段失效了,TCP不会等待计时器超时再重传,TCP会直接启动快速重传(fast retransmit),直接重传。这一点,实际上就是以时间和数据量两个指标作为衡量重传的条件。

同样,还是用工具实践一下有意思一点,推荐使用WireShark,WireShark的Filter非常强大,在进行网络诊断的时候非常有用。WireShark会根据TCP header中的Sequence Number,分析出冗余ACK、快速重传等现象,具体点我。WireShark在Filter中输入tcp.analysis.fast_retransmission,就可以找出快速重传的报文段。

(未完待续)

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部