最近又重温了TCP/IP的知识,果真比第一次看的时候有感悟多了,那就写一点东西来总结一下。程序员
如今咱们主要了解计算机网络的两种模型:OSI模型和TCP/IP模型。须要注意的是因为OSI模型过于复杂致使难以实现,所以致使TCP/IP模型更早地应用在现实中。这也使得TCP/IP模型成为事实上的标准,而OSI仅仅是纸面上的标准。服务器
在OSI模型中,将计算机网络分红了7层,而在TCP/IP模型中则分红了4层,其各层对应关系以下表所示:网络
OSI | TCP/IP | 对应网络协议 | 所在位置 |
应用层 | 应用层 | TFTP, FTP, NFS, WAIS | 主机 |
表示层 | Telnet, Rlogin, SNMP, Gopher | ||
会话层 | SMTP, DNS | ||
传输层 | 传输层 | TCP, UDP | |
网络层 | 网际层 | IP, ICMP, ARP, RARP, AKP, UUCP | 媒介 |
数据链路层 | 网络接口层 | FDDI, Ethernet, Arpanet, PDN, SLIP, PPP | |
物理层 | IEEE 802.1A, IEEE 802.2到IEEE 802.11 |
在整个计算机网络体系中,最核心的当属是位于传输层的TCP与UDP协议了。由于他们位于主机协议栈的最底层,向上方应用层提供不一样的数据交付方式。spa
由于UDP协议相对TCP协议来讲相对简单,就先回顾一下UDP协议。计算机网络
UDP的全称也叫作用户数据报协议(User Datagram Protocal),它有如下几个值得注意的特色:3d
UDP不能保证可靠传输,也就更不能保证所发送的数据的到达顺序,它所实现的是尽最大的努力交付。指针
UDP是面向数据报文的、无链接的协议,所以它的开销低而且发送器前的时延小(由于不用创建链接啊),面向报文也使得IP层在传输UDP协议的报文时既不会拆分也不会合并。视频
UDP能够支持一对1、一对多、多对1、多对多的通讯。blog
UDP没有拥塞控制功能,它的发送速率不会随着网络出现的拥塞而下降,因此它的实时性较好。这也是许多视频聊天应用采用它的缘由。接口
以下是UDP报文头部格式
其中从1到8字节分别是来源端口号、目的端口号、报文长度、检验和,每一个字段各占两字节。
UDP的通讯方式较为简单,发送端发送完一个报文继续发送下一个,待将全部报文发送完毕通讯就结束了。
接收方也是如此。
传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向链接的、可靠的、基于字节流的传输层通讯协议。
TCP协议所要实现的功能是端到端之间的可靠传输,所以,相较于UDP协议而言,TCP协议要复杂的多。
相对于UDP协议,TCP协议有下面的几个特色:
TCP协议保证可靠传输,也就是说发送的数据是什么样,接收的数据也是什么样。
TCP协议是有链接的、面向数据流的协议。有链接是说数据传送前通讯双方须要创建链接、通讯完毕后须要断开链接,不过这里所提到的链接都是逻辑上的链接。面向数据流的意思是说发送方应用程序发送的数据是什么顺序,接收方应用读取的接收到的数据也是什么顺序。
TCP协议提供的是端到端的通讯,也就是说一条TCP链接只能提供一对一的通讯。不过,一个应用能够同时创建多条TCP链接来实现与多个目标的通讯。
TCP协议提供拥塞控制功能,会在网络情况良好的状况下适当提升发送/接收速率,反之则适当下降发送/接收速率。这样,将会提升对网络的利用率。
此外,还须要注意的是,TCP提供的是全双工的通讯。
要理解TCP协议中各功能的实现,要先从TCP的数据封包结构开始。
下面的图片就是TCP数据封包的结构示意图:
各个字段功能以下:
来源端口(2字节):标识来源端口号。
目的端口(2字节):标识目的端口号。
序列号码(4字节):代表此封包在字节流中的顺序号。由于TCP是面向字节流的协议,须要保证最终的数据顺序与发送方发送的顺序一致,因此须要这个字段来代表该封包在字节流中的位置。
确认号码(4字节):对此前按顺序收到的最后一个封包的序列号码的确认。
例如:当33号之前的封包都已经完整的到达了后,就向发送方发送确认号码为34(确认的封包号码+1)来告诉发送方:33号之前的全部封包我都已经收到了,能够向我发送34号封包了。
这里要注意: 若是收到了3四、3五、37号封包而未收到36号封包,则向发送端发送确认号为35的封包。
总之要记住,确认号=N,表示N-1及其以前的封包都已经收到。
报头长度(1字节):指示报文头部的长度。
可是须要注意,这里的单位是4字节。例如,这个属性的值是15的话则说明报文头部的长度是60(15*4)字节。
保留字段(10位):暂时没打算好干啥用,一概置0。
标识符(6位):每一个比特位分别表示以下标识符:
URG—为1表示高优先级数据包,紧急指针字段有效。
ACK—为1表示确认号字段有效。TCP规定链接创建后,全部传送的报文段都必须把该字段置为1。
PSH—为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
RST—为1表示出现严重差错。可能须要重现建立TCP链接。还能够用于拒绝非法的报文段和拒绝链接请求。
SYN—为1表示这是链接请求或是链接接受请求,用于建立链接和使顺序号同步
FIN—为1表示发送方没有数据要传输了,要求释放链接。
窗口(2字节):表示从确认号开始,本报文的源方能够接收的字节数,即源方接收窗口大小。用于流量控制。
校验和(2字节)对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。这是一个强制性的字段。
紧急指针(2字节):本报文段中的紧急数据的最后一个字节的序号。
选项字段(最多40字节):每一个选项的开始是1字节的kind字段,说明选项的类型。
其中上面的三、四、七、8是重点。
为了搞明白下面要说的TCP的一些机制,首先须要知道TCP协议可以实现可靠传输的一个基本的原理--超时重传。
说来很简单,其实就是收到当接收方收到一个数据封包的时候就向发送方发送一个确认数据封包。而当发送方发送完一个数据封包通过一段时间没有收到接收方的确认封包时,就会将上一个封包再次向接收方发送一次。
固然,TCP中真正的机制比这个要复杂的多,可是基于的原理都是同样的。
在说TCP链接以前先插播一个小故事。
说是有一天,一个程序员到酒吧去喝酒,因而跟服务员之间发生了以下的对话。
程序员:我要一瓶酒。
服务员:你肯定你要一瓶酒?
程序员:我肯定我要一瓶酒。
因而服务员就给了程序员一瓶酒。
是否是很罗嗦?没错,这就是典型的TCP链接创建的过程。以下面的图:
图中的小人就是客户端,另外一边不用说也知道就是服务器端。图中画的比较简略,大概过程是下面这样:
下面过程当中,ACK表示上面说的TCP包头中的确认标识,ack表示确认号(4字节那个)。
客户端向服务器发送创建链接请求数据包,其中包头内容SYN=1,seq=x(本身随机挑选的起始序号)。(我要一瓶酒)
服务器收到请求后,若是赞成创建链接,就向客户端发送赞成创建链接请求数据封包,其包头内容SYN=1,ACK=1,ack=x+1(还记得为何吗),seq=y(一样也是本身随机挑选的)。(你肯定你要一瓶酒吗)
客户端收到服务器发来的确认请求后,也向服务器发送确认封包,其内容ACK=1,ack=y+1(原理同上),seq=x+1(毕竟已经发送过seq=x的封包了),随后客户端就进入链接创建状态,而服务器就在收到这个确认封包后也进入链接创建状态。(我肯定我要一瓶酒)
以上步骤就是俗称的“TCP三次握手”。
固然,最初的时候服务器确定是处于监听状态啦,要否则怎么可以对客户端的数据封包作出回应呢。
要注意的是,这里有个很经典的问题就是为何在收到服务器的确认封包后还要再向服务器发送一个确认封包呢?
这主要是由于TCP协议的下层网络是不可靠的,也就是说数据封包可能丢失也可能滞留在某个节点很长时间。
因此这就有一种可能就是客户端发送给服务器的封包在网络中滞留了,这样客户端固然也就不会收到服务器发来的确认封包。还记得TCP有个超时重传机制吗?没错,这个时候客户端是觉得本身发出去的封包在网络中是丢了的,因而过一段时间又会重传刚才的封包。
幸运的是,此次重传的封包十分顺利的到达了服务器,因而服务器也十分顺利的向客户端发出了确认封包。原本就要愉快的创建链接了,但是天有不测风云,刚才滞留的请求封包此时到达了服务器这里。
这个时候服务器就懵了,这究竟是客户端又要跟我创建一次链接仍是刚才滞留的封包又给了我呢?
因而这个时候就须要客户端再发送一个确认封包给服务器了。
固然,有链接创建,就有链接释放,客户端与服务器之间的链接释放过程大概是下面这个样子的。
跟创建链接的时候差很少,大概过程大概向下面这样:
客户端向服务器发送链接请求释放封包,封包内容为FIN=1,seq=u。
服务器收到后,决定要跟客户端释放链接,但是还有数据没传送完啊,就先发一个封包告诉客户端我能够释放链接,你能够不用向我发送数据了,但是我还有数据没有传送完,因此在我告诉你结束以前你得一直接收个人数据(别忘了,TCP但是全双工的)。因此所发送封包内容为:ACK=1,ack=u+1,seq=v。(FIN=0表示我还有数据要发送)
服务器发送完数据后,告诉客户端我都发送完了,能够结束了。因而发送封包为FIN=1,ACK=1,ack=u+1(这里得注意啦),seq=w(中间还传输过数据,因此可能不是v+1)。
客户端收到服务器的确认后,再次向服务器发送确认,内容是ACK=1,ack=w+1,seq=u+1。
发送完上面的确认封包后,客户端再等一段时间(2MSL)后,就断开链接。至此,链接正常释放。
如上步骤就是俗称的“TCP4次挥手”。
这里之因此是4次,主要是与创建链接时相比,服务器的确认和结束被分红了两个封包分别发送了出去。
固然,这里也有个比较经典的问题就是客户端为何在发送完最后一个封包后还要再等待一段时间?
这里也主要是由于TCP协议下层的网络并非很可靠,有可能客户端发出的最后一个封包在路上丢了而致使服务器等待很长世间浪费服务器资源。因而就让客户端再等待一段时间,这样当服务器收不到客户端发来的确认封包时,还会再重传一个链接结束封包,此时的客户端再次受到这个链接结束封包后还能够再重传一次确认封包来让服务器正常结束链接。这样,就不会白白浪费服务器资源了。
最后,再从整个网络的范围来看,一个数据封包究竟是要通过怎样的旅程才会从出发地到达目的地呢?
以TCP协议为例,当TCP协议接到上层应用层交付下来的数据封包后,就在这个数据封包的前面加上TCP的头部。
而后,再交付给下层的网络层。
网络层接收到上层传输层传递下来的封包后,就在封包的头部加上IP协议的头部和网际接口层的首部和头部后通过层层路由,最终到达距离目的主机最近的路由器。
而后距离目的主机最近的路由器再对数据包进行解包,去掉网际接口层和网络层的封装后将数据包送到目的主机的传输层(TCP接收缓冲池),再由目的主机的传输层交给上层的应用层。
一图以蔽之: