Fork me on GitHub

TCP IP 学习笔记

概念

为什么需要TCP/IP协议

电脑运行着不同的操作系统,想发送不同的信息出去,好像就是全国各地的方言一样,即使表达相同的意思,也不能理解它们,需要使用一个通用的方式,让两个语言不同的人能够就行交流。
所以它们需要一些相通的东西进行交流,所以普通话就产生了,呸,跑题了,所以TCP/IP 就这样诞生了。

TCP/IP不是一个协议,而是一个协议族的统称。里面包括了IP协议,IMCP协议,TCP协议,以及我们更加熟悉的http、ftp、pop3协议等等。电脑有了这些,就学会了普通话,可以和全国各地的人交流了。

TCP/IP协议分层

TCP工作在网络OSI的七层模型中如下所示:
image

  1. 应用层:向用户提供一组常用的应用程序,如电子邮件(简单邮件传输协议,SMTP),文件传输访问(文件传输协议,FTP),远程登录(TELNET)等。
  2. 传输层:提供应用程序间的通信。其功能包括: 格式化信息流;提供可靠传输。
  3. 网络层(网际层):这里有 IP 协议类似的协议,负责相邻计算机之间的通信。功能主要包括三方面:
    1. 处理来自传输层的分组发送请求:收到请求之后,将分组装入 IP 数据报,填充报头,选择去往信宿机的路径,然后将数据报发往适当的网络接口;
    2. 处理输入数据报:首先检查其合法性,然后进行寻址:如果该数据包已经到达信宿机,则去掉报头,将剩下一部分交给适当的传输协议;如果该数据包尚未到达信宿机,则转发该数据报;
    3. 处理路径、流控、拥塞等问题
  4. 网络接口层:这个层次为待传送的数据加入一个以太网协议头,并进行CRC编码,数据传输做准备。
  5. 硬件层:这个层次的定义包括网线的制式,网卡的定义等等

常识

  1. ip 地址:互联网地址,网络上每一个节点都必须有一个独立的Internet地址(也叫做IP地址)。。现在,通常使用的IP地址是一个32bit的数字,也就是我们常说的IPv4标准,这32bit的数字分成四组,也就是常见的255.255.255.255的样式。IPv4标准上,地址被分为五类,我们常用的是B类地址。具体的分类请参考其他文档。需要注意的是IP地址是网络号+主机号的组合,这非常重要。
  2. 域名系统:域名系统是一个分布的数据库,它提供将主机名转换成IP地址的服务。
  3. RFC:tcp/ip协议的标准文档;
  4. 端口号:用在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 的三次握手

image

三次握手详解 TCP 是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在 TCP / IP 协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的。 三次握手的目的是同步连接双方的序列号和确认号并交换 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 NumberAcknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment NumberSequence 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技术,不需要服务器中转。

      image

------本文结束 🖐 感谢阅读------
0%