关于TCP/IP,运维必须知道和理解的十个问题互联网的核心协议。基于TCP/IP的参考模型将协议分为四层,即链路层、网络层、传输层和应用层。下图显示了TCP/IP模型和OSI模型的层级对比。TCP/IP协议族是从上到下逐层封装的。最上层是应用层,包括http、ftp等大家熟悉的协议。第二层是传输层,著名的TCP和UDP协议都在这一层。第三层是网络层,IP协议负责在数据中添加IP地址等数据,以确定传输的目的地。第四层是数据链路层。该层为要传输的数据添加以太网协议头,并进行CRC编码,为最终的数据传输做准备。上图清楚地展示了TCP/IP协议中各层的作用,而TCP/IP协议的通信过程实际上对应的是数据出栈和出栈的过程。在堆叠的过程中,数据发送方在每一层不断封装头尾,并添加一些传输信息,以保证能够传输到目的地。在堆叠的过程中,数据接收方在每一层不断去除头尾,得到最终传输的数据。上图以HTTP协议为例进行了详细说明。2.数据链路层物理层负责0、1比特流与物理设备电压电平的交换,以及灯的闪烁。数据链路层负责将0和1的序列分成数据帧,从一个节点传输到另一个相邻节点。这些节点由MAC(MAC,物理地址,一台主机会有一个MAC地址)唯一标识。封装成帧:将网络层数据报加上头和尾,封装成帧,帧头包括源MAC地址和目的MAC地址。透明传输:零位填充,转义字符。可靠传输:很少用在错误率极低的链路上,但无线链路WLAN会保证可靠传输。错误检测(CRC):接收器检测错误并在发现错误时丢弃该帧。三、网络层1、IP协议IP协议是TCP/IP协议的核心。所有的TCP、UDP、IMCP、IGMP数据都以IP数据格式传输。需要注意的是,IP并不是一个可靠的协议,也就是说IP协议不提供数据不通信后的处理机制,这被认为是上层协议:TCP或UDP不得不做的事情。1.1IP地址在数据链路层,我们一般通过MAC地址来标识不同的节点,在IP层,我们也有类似的地址标识,就是IP地址。32位的IP地址分为网络位和地址位。这样可以减少路由器中路由表记录的数量。通过网络地址,可以将具有相同网络地址的终端限制在同一范围内。那么路由表只需要维护这个网络地址的一个方向,就可以找到对应的终端。A类IP地址:0.0.0.0~127.0.0.0B类IP地址:128.0.0.1~191.255.0.0C类IP地址:192.168.0.0~239.255.255.01.2这里只介绍IP协议头:八-位TTL字段。该字段指定数据包在被丢弃之前经过了多少条路由。IP数据包每经过一个路由器,该数据包的TTL值就会减1,当该数据包的TTL变为0时,该数据包将被自动丢弃。该字段的最大值为255,即一个协议报文经过路由器255次后将被丢弃。根据系统的不同,这个数字是不同的,通常是32或64。2.ARP和RARP协议ARP是一种根据IP地址获取MAC地址的协议。ARP(AddressResolution)协议是一种解析协议。本来主机并不知道这个IP对应主机的哪个接口。当主机要发送IP数据包时,首先会查看自己的ARP缓存(即AnIP-MAC地址对应表缓存)。如果查询的IP-MAC值对不存在,主机会向网络发送一个ARP协议广播包,其中包含要查询的IP地址,所有直接收到广播包的主机都会查询自己的IP地址,如果某台收到广播包的主机发现自己符合条件,就会准备一个包含自己MAC地址的ARP包,发送给发送ARP广播的主机。广播主机收到ARP包后,会更新自己的ARP缓存(即存放IP-MAC对应表的地方)。发送广播的主机将使用新的ARP缓存数据为发送数据包准备数据链路层。RARP协议的工作与此相反,不再详述。3.ICMP协议IP协议不是可靠的协议,它不保证数据一定会被传送。那么,保证数据传递的工作自然要交由其他模块来完成。其中一个重要的模块是ICMP(Internet控制消息)协议。ICMP不是高层协议,而是IP层协议。传输IP数据包时发生错误。例如主机不可达、路由不可达等,ICMP协议会将错误信息打包回传给主机。给主机一个处理错误的机会,这就是为什么可以使用构建在IP层之上的协议来实现安全性的原因。第四,pingping可以说是ICMP最著名的应用,它是TCP/IP协议的一部分。使用“ping”命令检查网络是否连通,可以帮助我们分析判断网络故障。例如:当我们的一个网站无法访问时。通常ping这个网站。ping将回显一些有用的信息。大致信息如下:ping这个词来自声纳定位,而这个程序正是这样做的。它使用ICMP协议数据包来检测另一台主机是否可达。其原理是使用类型代码为0的ICMP发送请求,收到请求的主机以类型代码为8的ICMP进行响应。5.TracerouteTraceroute是检测本机与目的主机之间路由的重要工具,并且它也是最方便的工具。Traceroute的原理非常非常有意思。收到目的主机的IP后,首先向目的主机发送一个TTL=1的UDP数据包,第一个经过的路由器收到这个数据包后,自动发送TTL减1,经过TTL变为0,路由器丢弃该数据包,同时向主机生成主机不可达的ICMP数据报。主机收到这个数据报后,向目的主机发送一个TTL=2的UDP数据报,然后刺激第二个路由器向该主机发送一个ICMP数据报。依此类推,直到到达目的主机。这样traceroute就得到了所有路由器的IP。6.TCP/UDPTCP/UDP同为传输层协议,但各自有不同的特点和不同的应用场景。下面以图表的形式进行对比分析。面向消息面向消息的传输方式是应用层将消息发送给UDP,UDP原样发送,即一次发送一条消息。因此,应用程序必须选择合适的消息大小。如果数据包太长,IP层需要分片,降低效率。如果太短,就是IP太小。如果字节流是面向字节流的,虽然应用程序和TCP交互的是一次一个数据块(不同大小),但是TCP把应用程序看成是一系列无结构的字节流。TCP有一个缓冲区。当应用程序传输的数据块过长时,TCP可以将其分成较短的块再传输。关于拥塞控制和流量控制,是TCP的重点,后面会讲到。TCP和UDP协议的某些应用什么时候应该使用TCP?当对网络通信的质量有要求时,例如:必须将整个数据准确无误地传送给对方,常用于一些可靠的应用,如HTTP、HTTPS、FTP等文件传输协议、POP、SMTP等邮件传输协议。什么时候应该使用UDP?当网络通信质量不高,又要求网络通信速度尽可能快时,可以使用UDP。7.DNSDNS(DomainNameSystem,域名系统),互联网上的分布式数据库,将域名和IP地址相互映射,使用户更方便地访问互联网,而不必记住可以直接访问的IP号由机器字符串读取。通过主机名最终得到主机名对应的IP地址的过程称为域名解析(或主机名解析)。DNS协议运行在UDP协议之上,使用端口号53。八、TCP连接的建立和终止1、三次握手TCP是面向连接的。无论哪一方向另一方发送数据,都必须先在双方之间建立连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,通过三次握手来初始化连接。三次握手的目的是同步双方的序号和确认号,交换TCP窗口大小信息。第一次握手:建立连接。客户端发送一个连接请求报文段,设置SYN位为1,SequenceNumber为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;第二次握手:服务器收到SYN报文段。服务端收到客户端的SYN报文段后需要对SYN报文段进行确认,将AcknowledgementNumber设置为x+1(SequenceNumber+1);同时需要自己发送SYN请求报文,并将SYN位设置为1,SequenceNumber为y;服务器将上述所有信息放入一个报文段(即SYN+ACK报文段)一起发送给客户端。此时服务器进入SYN_RECV状态;第三次握手:客户端收到服务器发来的SYN+ACK报文段。然后将AcknowledgementNumber设置为y+1,向服务器发送一个ACK报文段。报文段发送完毕后,客户端和服务器都进入ESTABLISHED状态,完成TCP三次握手。为什么要进行三次握手?为了防止突然向服务器发送无效的连接请求段,产生错误。具体例子:“无效连接请求段”是在这样一种情况下产生的:客户端发送的第一个连接请求段并没有丢失,而是长时间停留在某个网络节点,以至于延迟到某个时间连接释放后到达服务器。原来这是一个已经过期的段。但是,服务端在收到无效的连接请求报文后,误认为是客户端再次发送的新的连接请求。然后向客户端发送确认消息段,同意建立连接。假设不使用“三次握手”,只要服务器发送确认,就建立了新的连接。由于客户端还没有发出建立连接的请求,所以会忽略服务器的确认,不会向服务器发送数据。但是服务端认为新的传输连接已经建立,一直等待客户端发送数据。这样就浪费了服务器的很多资源。“三次握手”的方法可以防止上述现象的发生。比如刚才的情况,客户端不会发送确认给服务器的确认。由于服务端没有收到确认,就知道客户端没有请求建立连接。》2、四次挥手,客户端和服务器端通过三次握手建立TCP连接后,当数据传输完成后,必须断开TCP连接。那么TCP断开连接就有了玄机“四次断手”.第一次分手:主机1(可以是客户端也可以是服务器),设置SequenceNumber,发送一个FIN报文段给主机2;此时主机1进入FIN_WAIT_1状态;这意味着主机1没有数据请求发送给主机2;第二次分手:主机2收到主机1发送的FIN报文段,向主机1返回ACK报文段,AcknowledgementNumber为SequenceNumber加1;主机1进入FIN_WAIT_2状态;主持人2告诉主持人1我“同意”您的关闭请求;第三次分手:主机2向主机1发送FIN报文段,请求关闭连接,主机2进入LAST_ACK状态;第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,随后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文后,关闭连接;此时主机1还在等待2MSL,如果没有收到回复,证明服务器已经正常关闭。好吧,主机1也可以关闭连接。为什么分手四次?TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP是全双工模式,也就是说当主机1发送一个FIN报文段的时候,只是说明主机1没有数据要发送,主机1告诉主机2自己的数据已经全部发送完了;但是,此时主机1仍然可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送,但主机2仍然可以向主机1发送数据;当主机2也发送了FIN报文段时,说明主机2没有数据要发送,它就会告诉主机1我没有数据要发送,然后双方就会愉快的中断TCP连接。为什么要等待2MSL?MSL:MaximumSegmentLifetime,这是任何段在被丢弃之前可以在网络中存在的最长时间。原因有二:保证TCP协议的全双工连接能够可靠关闭,保证这个连接的重复数据段从网络中消失。第一点:如果主机1直接CLOSED,那么由于IP协议的不可靠性或者其他原因导致主机2没有收到主机1的最后一个ACK。那么主机2会在结束后继续发送FIN暂停。此时由于主机1处于CLOSED状态,所以无法找到重发的FIN对应的连接。所以主机1并没有直接进入CLOSED,而是保持TIME_WAIT。再次收到FIN时,可以确保对方收到ACK,最终正确关闭连接。第二点:如果主机1直接CLOSED,然后又向主机2发起新的连接,我们不能保证这个新连接的端口号和刚刚关闭的连接的端口号不一样。也就是说,有可能新连接和旧连接的端口号是一样的。一般来说不会有问题,但是还是有特殊情况:假设新连接的端口号和已经关闭的旧连接的端口号一样,如果之前连接的一些数据还卡在在网络中,这些延迟数据是建立起来的。新连接到达主机2后,由于新连接和旧连接的端口号相同,TCP协议认为延迟数据属于新连接,从而与主机2的真实数据包混淆新连接。因此TCP连接在TIME_WAIT状态下要等待2倍的MSL,这样可以保证这个连接的所有数据从网络上消失。九、TCP流量控制如果发送方发送数据的速度太快,接收方可能来不及接收,就会造成数据丢失。所谓流量控制就是让发送方的发送速率不要太快,让接收方有时间接收。发送方的流量控制可以很容易地通过使用滑动窗口机制在TCP连接上实现。让A给B发送数据,当连接建立后,B告诉A:“我的接收窗口是rwnd=400”(这里的rwnd表示接收窗口)。因此,发送方的发送窗口不能超过接收方给定的接收窗口的值。请注意,TCP的窗口单位是字节,而不是段。假设每个段的长度为100字节,数据段序号的初始值设置为1。大写的ACK表示包头中的确认位ACK,小写的ack表示确认字段的值ack。从图中可以看出,B进行了3次流控。window第一次缩小到rwnd=300,第二次缩小到rwnd=100,最后缩小到rwnd=0,即不允许发送方再发送数据。这种导致发送方暂停发送的状态将一直持续到主机B重新发出一个新的窗口值。B发送给A的三个报文段都设置了ACK=1,只有ACK=1时确认号字段才有意义。TCP为每个连接都有一个持久性定时器(persistencetimer)。只要TCP连接的一侧收到另一侧的零窗口通知,持续时间计时器就会启动。如果持久定时器设置的时间超时,则发送零窗口控制检测消息段(携带1字节数据),接收消息段的一方重置持久定时器。10.TCP拥塞控制发送端维护一个拥塞窗口cwnd(congestionwindow)的状态变量。拥塞窗口的大小取决于网络拥塞的程度,并且是动态变化的。发送方使他的发送窗口等于拥塞窗口。发送方控制拥塞窗口的原则是:只要网络不发生拥塞,就会增加拥塞窗口以发送更多的数据包。但只要网络拥塞,就会减小拥塞窗口以减少注入网络的数据包数量。慢启动算法:当主机开始发送数据时,如果立即向网络注入大量数据字节,可能会造成网络拥塞,因为此时网络的负载还不明确。因此,更好的方法是先检测,即发送窗口由小到大逐渐增大,即拥塞窗口的值由小到大逐渐增大。通常,当报文段刚开始发送时,首先将拥塞窗口cwnd设置为最大报文段的MSS值。在收到对新消息段的确认后,拥塞窗口最多增加一个MSS值。使用这种方法逐渐增大发送方的拥塞窗口cwnd,可以使数据包注入网络的速率更加合理。在每一轮传输之后,拥塞窗口cwnd加倍。传输回合中经过的时间实际上是往返时间RTT。但是“发送轮”更强调:拥塞窗口cwnd允许发送的报文段被连续发送,最后一个发送字节的确认已经收到。另外,slowstart的“慢”并不是指cwnd的增长速度慢,而是指在TCP开始发送报文段的时候设置cwnd=1,让发送方一开始只发送一个报文段(目的是测试看看网络的拥塞情况),然后逐渐增加cwnd。为了防止拥塞窗口cwnd增长过快导致网络拥塞,还需要设置一个慢启动阈值ssthresh状态变量。慢启动阈值ssthresh的用法如下:当cwnd
