概念
为什么需要TCP/IP协议
电脑运行着不同的操作系统,想发送不同的信息出去,好像就是全国各地的方言一样,即使表达相同的意思,也不能理解它们,需要使用一个通用的方式,让两个语言不同的人能够就行交流。
所以它们需要一些相通的东西进行交流,所以普通话就产生了,呸,跑题了,所以TCP/IP 就这样诞生了。
TCP/IP不是一个协议,而是一个协议族的统称。里面包括了IP协议,IMCP协议,TCP协议,以及我们更加熟悉的http、ftp、pop3协议等等。电脑有了这些,就学会了普通话,可以和全国各地的人交流了。
TCP/IP协议分层
TCP工作在网络OSI的七层模型中如下所示:
应用层
:向用户提供一组常用的应用程序,如电子邮件(简单邮件传输协议,SMTP),文件传输访问(文件传输协议,FTP),远程登录(TELNET)等。传输层
:提供应用程序间的通信。其功能包括: 格式化信息流;提供可靠传输。网络层(网际层)
:这里有 IP 协议类似的协议,负责相邻计算机之间的通信。功能主要包括三方面:- 处理来自传输层的分组发送请求:收到请求之后,将分组装入 IP 数据报,填充报头,选择去往信宿机的路径,然后将数据报发往适当的网络接口;
- 处理输入数据报:首先检查其合法性,然后进行寻址:如果该数据包已经到达信宿机,则去掉报头,将剩下一部分交给适当的传输协议;如果该数据包尚未到达信宿机,则转发该数据报;
- 处理路径、流控、拥塞等问题;
网络接口层
:这个层次为待传送的数据加入一个以太网协议头,并进行CRC编码,数据传输做准备。硬件层
:这个层次的定义包括网线的制式,网卡的定义等等
常识
ip 地址
:互联网地址,网络上每一个节点都必须有一个独立的Internet地址(也叫做IP地址)。。现在,通常使用的IP地址是一个32bit的数字,也就是我们常说的IPv4标准,这32bit的数字分成四组,也就是常见的255.255.255.255的样式。IPv4标准上,地址被分为五类,我们常用的是B类地址。具体的分类请参考其他文档。需要注意的是IP地址是网络号+主机号的组合,这非常重要。域名系统
:域名系统是一个分布的数据库,它提供将主机名转换成IP地址的服务。RFC
:tcp/ip协议的标准文档;端口号
:用在TCP,UDP上的一个逻辑号码,并不是一个硬件端口,我们平时说把某某端口封掉了,也只是在IP层次把带有这个号码的IP包给过滤掉了而已。
TCP 的报文格式
参考TCP报文格式
Source Port, Destination Port(源端口号,目的端口号)
:分别占用 16 位,用于区别主机中的不同进程;由于 IP 地址用来区分不同主机,所以源端口号、目的端口号与 IP 首部中的源 IP 地址和目的 IP 地址,技能确定唯一的一个 TCP 连接;Sequence Number(发送序号)
:32 位数据,用来标识从 TCP 发送端向 TCP 接收端发送的数据字节流,它表示在这个报文段中的第一个数据字节在数据流中的序号,主要用来解决网络报乱序问题;Acknowledgment Number(确认序号)
:占用 32 位,由接收端的计算机使用,将分段的报文重组成最初形式;如果设置了控制位 ACK = 1,则这个值表示下一个准备接受的包的序列码;Offset(数据偏移量)
:占用 4 位,给出首部中 32bit 字的数目,需要这个值是因为任选字段的长度是可变的(如果没有任选字段,正常的长度是 20 字节);Reserved(保留位)
:占用 6 位,且必须是 0,为了将来定义新的用途而保留;TCP Flags(TCP 标志位)
:用于标志 TCP 的某些状态,它们中的多个可同时被设置为 1,主要用于操控 TCP 的状态机,6 个标志位依次为 URG, ACK, PSH, RST, SYN, FIN。每个标志位的意义如下:
URG
:紧急标志 (Urgent),该标志表示 TCP 包的紧急指针域有效(后面将会说到紧急指针域的内容),用来保证 TCP 连接不被中断,并督促中间层设备要尽快处理这些数据;ACK
:确认标志 (Acknowledge),该标志表示应答域有效,就是说前面提到的 TCP 应答信号会包含在 TCP 数据包中;ACK 可以由两个取值( 0/1 ):应答域有效为1,反之为0;PSH
:推标志 (Push),表示 Push 操作,即在数据报到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队;RST
:复位标志 (Reset),用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据报;SYN
:同步标志 (Synchronize),用来建立连接。该标志经常与 ACK 标志搭配使用。
FIN
:结束标志 (Finish),表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描;
参考TCP 协议详解
TCP 的三次握手
三次握手详解 TCP 是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在 TCP / IP 协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的。 三次握手的目的是同步连接双方的序列号和确认号并交换 TCP 窗口大小信息。这就是面试中经常会被问到的 TCP 三次握手。
第一次握手:建立连接。客户端发送连接请求报文段,将SYN
位置为1,Sequence Number
为x;然后,客户端进入SYN_SEND
状态,等待服务器的确认;
第二次握手:服务器收到SYN
报文段。服务器收到客户端的SYN
报文段,需要对这个SYN
报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);
同时,自己自己还要发送SYN请求信息,将SYN
位置为1,Sequence Number
为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK
报文段)中,一并发送给客户端,此时服务器进入SYN_RECV
状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number
设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED
状态,完成TCP三次握手。
完成了三次握手,客户端和服务器端就可以开始传送数据。
主要是注意为什么要进行第三次连接,这里很容易挖坑,书中解释说:
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
“已失效的连接请求报文段”的产生在这样一种情况下:客户端发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务器。本来这是一个早已失效的报文段,但服务器收到此失效的连接请求报文段后,就误认为是客户端再次发出的一个新的连接请求。于是就向客户端发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要服务器发出确认,新的连接就建立了。由于现在客户端并没有发出建立连接的请求,因此不会理睬服务器的确认,也不会向服务器发送数据。但服务器却以为新的运输连接已经建立,并一直等待客户端发来数据。这样,服务器的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,客户端不会向服务器的确认发出确认。服务器由于收不到确认,就知道客户端并没有要求建立连接。”
其实主要目的就是为了防止服务端一致等待导致资源浪费。
TCP 的四次分手
具体还是参考上面提供的这个链接通俗大白话来理解TCP协议的三次握手和四次分手
第一次分手:主机1(可以使客户端,也可以是服务器端),设置Sequence Number
和Acknowledgment Number
,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1
状态;这表示主机1没有数据要发送给主机2了;
第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK
报文段,Acknowledgment Number
为Sequence Number
加1;主机1进入FIN_WAIT_2
状态;主机2告诉主机1,我也没有数据要发送了,可以进行关闭连接了;
第三次分手:主机2向主机1发送FIN
报文段,请求关闭连接,同时主机2进入CLOSE_WAIT
状态;
第四次分手:主机1收到主机2发送的FIN
报文段,向主机2发送ACK
报文段,然后主机1进入TIME_WAIT
状态;主机2收到主机1的ACK
报文段以后,就关闭连接;此时,主机1等待2MSL
后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。
FIN_WAIT_1
: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。(主动方)FIN_WAIT_2
:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接。(主动方)CLOSE_WAIT
:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。(被动方)LAST_ACK
: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。(被动方)TIME_WAIT
: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FINWAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)CLOSED
: 表示连接中断。
了解了基础,好好整理下,面试时候该要上场的。
面试题
三次握手和四次挥手的流程上面已经提过了。
TCP协议和UDP协议的区别是什么?
- TCP协议是有连接的,有连接的意思是开始传输实际数据之前TCP的客户端和服务器端必须通过三次握手建立连接,会话结束之后也要结束连接。而UDP是无连接的
- TCP协议保证数据按序发送,按序到达,提供超时重传来保证可靠性,但是UDP不保证按序到达,甚至不保证到达,只是努力交付,即便是按序发送的序列,也不保证按序送到。
- TCP协议所需资源多,TCP首部需20个字节(不算可选项),UDP首部字段只需8个字节。
- TCP有流量控制和拥塞控制,UDP没有,网络拥堵不会影响发送端的发送速率
- TCP是一对一的连接,而UDP则可以支持一对一,多对多,一对多的通信。
- TCP面向的是字节流的服务,UDP面向的是报文的服务。
为什么要三次握手,两次,四次行不行?
三次握手:
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,今天balabala……”
两次握手:
“喂,你听得到吗?”
“我听得到,你听得到吗?”
‘’今天balabala………‘’
“……谁在说话?”
“……”
四次握手:
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,你能听到我吗?”
“……不想跟傻逼说话”(摘自知乎)
总的来说就是三次刚好,多一次浪费;少一次不够,会让服务端一直等待发送消息,白白浪费了资源。四次挥手释放连接时,等待2MSL的意义?
假设 A 是客户端, B 是服务端
- 第一,为了保证A发送的最有一个ACK报文段能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN和ACK报文段的确认。B会超时重传这个FIN和ACK报文段,而A就能在2MSL时间内收到这个重传的ACK+FIN报文段。接着A重传一次确认。
- 第二,就是防止上面提到的已失效的连接请求报文段出现在本连接中,A在发送完最有一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。
常见的应用中有哪些是应用TCP协议的,哪些又是应用UDP协议的,为什么它们被如此设计?
以下应用一般或必须用udp实现?
- 多播的信息一定要用udp实现,因为tcp只支持一对一通信。
- 如果一个应用场景中大多是简短的信息,适合用udp实现,因为udp是基于报文段的,它直接对上层应用的数据封装成报文段,然后丢在网络中,如果信息量太大,会在链路层中被分片,影响传输效率。
- 如果一个应用场景重性能甚于重完整性和安全性,那么适合于udp,比如多媒体应用,缺一两帧不影响用户体验,但是需要流媒体到达的速度快,因此比较适合用udp
- 如果要求快速响应,那么udp听起来比较合适
- 如果又要利用udp的快速响应优点,又想可靠传输,那么只能考上层应用自己制定规则了。
- 常见的使用udp的例子:ICQ,QQ的聊天模块。
以qq为例的一个说明
登陆采用TCP协议和HTTP协议,你和好友之间发送消息,主要采用UDP协议,内网传文件采用了P2P技术。总来的说:
1.登陆过程,客户端client 采用TCP协议向服务器server发送信息,HTTP协议下载信息。登陆之后,会有一个TCP连接来保持在线状态。
2.和好友发消息,客户端client采用UDP协议,但是需要通过服务器转发。腾讯为了确保传输消息的可靠,采用上层协议来保证可靠传输。如果消息发送失败,客户端会提示消息发送失败,并可重新发送。
3.如果是在内网里面的两个客户端传文件,QQ采用的是P2P技术,不需要服务器中转。