zoukankan      html  css  js  c++  java
  • TCP数据报结构以及三次握手(图解)

    简要介绍

    TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接。
    客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。
    TCP建立连接时要传输三个数据包,俗称三次握手(Three-way Handshaking)。可以形象的比喻为下面的对话:

      • [Shake 1] 套接字A:“你好,套接字B,我这里有数据要传送给你,建立连接吧。”
      • [Shake 2] 套接字B:“好的,我这边已准备就绪。”
      • [Shake 3] 套接字A:“谢谢你受理我的请求。”

    TCP数据报结构

     具体内容参照

    https://www.cnblogs.com/cyx-b/p/12492872.html

    只对带阴影的几个字段重点说明一下:
    1) 序号:Seq(Sequence Number)序号占32位,用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。

    2) 确认号:Ack(Acknowledge Number)确认号占32位,客户端和服务器端都可以发送,Ack = Seq + 1。

    3) 标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:

      • URG:紧急指针(urgent pointer)有效。
      • ACK:确认序号有效。
      • PSH:接收方应该尽快将这个报文交给应用层。
      • RST:重置连接。
      • SYN:建立一个新连接。
      • FIN:断开一个连接。
    对英文字母缩写的总结:Seq 是 Sequence 的缩写,表示序列;Ack(ACK) 是 Acknowledge 的缩写,表示确认;SYN 是 Synchronous 的缩写,愿意是“同步的”,这里表示建立同步连接;FIN 是 Finish 的缩写,表示完成。

    连接的建立(三次握手)

    为了理解得更深刻,我查找了很多资料。

    ①知乎

    https://zhuanlan.zhihu.com/p/43838752

    TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种断点我们叫作套接字(socket),它的定义为端口号拼接到IP地址即构成了套接字,例如,若IP地址为192.168.4.16 而端口号为80,那么得到的套接字为192.168.4.16:80

    最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。

    1、TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;

    2、TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。

    3、TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。

    4、TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。

    5、当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。

     ②C语言中文网

    http://c.biancheng.net/cpp/html/3042.html

    使用 connect() 建立连接时,客户端和服务器端会相互发送三个数据包,请看下图:

    客户端调用 socket() 函数创建套接字后,因为没有建立连接,所以套接字处于CLOSED状态;服务器端调用 listen() 函数后,套接字进入LISTEN状态,开始监听客户端请求。

    这个时候,客户端开始发起请求:
    1) 当客户端调用 connect() 函数后,TCP协议会组建一个数据包,并设置 SYN 标志位,表示该数据包是用来建立同步连接的。同时生成一个随机数字 1000,填充“序号(Seq)”字段,表示该数据包的序号。完成这些工作,开始向服务器端发送数据包,客户端就进入了SYN-SEND状态。

    2) 服务器端收到数据包,检测到已经设置了 SYN 标志位,就知道这是客户端发来的建立连接的“请求包”。服务器端也会组建一个数据包,并设置 SYN 和 ACK 标志位,SYN 表示该数据包用来建立连接,ACK 用来确认收到了刚才客户端发送的数据包。
    服务器生成一个随机数 2000,填充“序号(Seq)”字段。2000 和客户端数据包没有关系。
    服务器将客户端数据包序号(1000)加1,得到1001,并用这个数字填充“确认号(Ack)”字段。
    服务器将数据包发出,进入SYN-RECV状态。

    3) 客户端收到数据包,检测到已经设置了 SYN 和 ACK 标志位,就知道这是服务器发来的“确认包”。客户端会检测“确认号(Ack)”字段,看它的值是否为 1000+1,如果是就说明连接建立成功。
    接下来,客户端会继续组建数据包,并设置 ACK 标志位,表示客户端正确接收了服务器发来的“确认包”。同时,将刚才服务器发来的数据包序号(2000)加1,得到 2001,并用这个数字来填充“确认号(Ack)”字段。
    客户端将数据包发出,进入ESTABLISED状态,表示连接已经成功建立。

    4) 服务器端收到数据包,检测到已经设置了 ACK 标志位,就知道这是客户端发来的“确认包”。服务器会检测“确认号(Ack)”字段,看它的值是否为 2000+1,如果是就说明连接建立成功,服务器进入ESTABLISED状态。

    至此,客户端和服务器都进入了ESTABLISED状态,连接建立成功,接下来就可以收发数据了。

    ③《TCP/IP入门经典》

    TCP 的一切操作都是在一个连接上下文的环境中完成的。TCP 通过连接发送和接收数据,而这个连接必须根据TCP的规则进行请求、打开和关闭。

    TCP 的功能之一是为应用程序提供访问网络的接口。这个接口是通过 TCP端口提供的,而为了通过端口提供连接,必须打开TCP与应用程序的接口。TCP支持以下两种打开状态。

    被动打开 :某个应用程序进程通知TCP准备通过TCP端口接收连接,这样就会打开TCP到应用程序的连接,从而为参与连接请求做准备。

    主动打开 :程序要求TCP发起与另一台计算机(处于被动打开状态)的连接,这就是主动打开状态。

    在通常情况下,想接收连接的应用程序(比如 FTP 服务器)会把自身及其 TCP 端口置于被动打开状态。在客户端计算机上,FTP客户端的TCP状态一般是关闭的,直到用户发起一个从FTP客户端到FTP服务器的连接,这对于客户端来说就是主动打开。处于主动打开状态的计算机(比如客户端)上的TCP软件会开始一些用于建立连接的信息交换,这种信息交换被称为“三次握手”。

    客户端是指向网络中的其他计算机请求或接收服务的计算机。

    服务器是指向网络中其他计算机提供服务的计算机。

    TCP发送的数据分段的长度是不定的。在一个数据分段内,每字节数据都被分配一个序列号。接收端计算机必须为接收到的每个字节数据都发送一个确认信号。因此,TCP通信是一种传输与确认的系统。TCP报头中的“序列号”和“确认号”字段(见前面小节的介绍)让通信的TCP软件能够定期更新传输的状态。

    实际上,数据分段中并不是为每个字节都单独编了一个序列号,而是在报头的“序列号”字段指定了数据分段第一个字节的序列号。

    这个规则有一个例外。如果数据分段是连接初期使用的,“序列号”字段里包含的是ISN,它的值比数据分段中第一个字节的序列号小 1(也就是说,第一个字节的序列号是ISN加1)。

    如果数据分段被成功接收,接收端计算机会利用“确认号”字段告诉发送端计算机它接收到哪个字节。在确认消息中,“确认号”字段的值是已接收的最后一个序列号加1。换句话说,“确认号”字段中的值是计算机准备接收的下一个序列号。

    如果发送端计算机没有在指定时间内收到确认消息,它会从已经得到确认的下一字节重新发送数据。

  • 相关阅读:
    防简单攻击iptables策略
    Iptables 防火墙常用配置
    9个常用iptables配置实例
    NFS服务的端口分配
    docker参数--restart=always的作用
    nginx的proxy_pass路径转发规则最后带/问题
    查看tomcat进程启动了多少个线程
    Tomcat 普通用户启动
    SSH远程执行脚本tomcat未启动
    mysql 前缀索引
  • 原文地址:https://www.cnblogs.com/cyx-b/p/12492537.html
Copyright © 2011-2022 走看看