网站编译成dll,动易 网站统计 首次打开,邢台专业做网站公司,濮阳市城乡一体化示范区西湖医院以下内容源于C语言中文网的学习与整理#xff0c;非原创#xff0c;仅作学习之用#xff0c;如有侵权请告知删除。 TCP#xff08;Transmission Control Protocol#xff0c;传输控制协议#xff09;是一种面向连接的、可靠的、基于字节流的通信协议#xff0c;数据在传…以下内容源于C语言中文网的学习与整理非原创仅作学习之用如有侵权请告知删除。 TCPTransmission Control Protocol传输控制协议是一种面向连接的、可靠的、基于字节流的通信协议数据在传输前要建立连接传输完毕后还要断开连接。 TCP如何保证可靠传输 1TCP在传输有效信息前要求通信双方必须先握手建立连接才能通信 2TCP的接收方收到数据包后会ack给发送方若发送方未收到ack会丢包重传 3TCP的有效数据内容会附带校验以防止内容在传递过程中损坏 4TCP会根据网络带宽来自动调节适配速率滑动窗口技术 5发送方会给各分割报文编号接收方会校验编号一旦顺序错误即会重传。 TCP数据报结构 在简述TCP数据传输之前先看一下TCP数据包结构。 带阴影的几个字段需要重点说明一下 1序号SeqSequence Number序号占32位用来标识从计算机A发送到计算机B的数据包的序号计算机发送数据时对此进行标记。 2确认号AckAcknowledge Number确认号占32位客户端和服务器端都可以发送Ack Seq 1。在数据传输阶段好像ACKSeq1传输的字节数目 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 的缩写表示完成。 一、建立连接【三次握手】 客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误为数据的传输开辟通道。 TCP建立连接时要传输三个数据包俗称三次握手Three-way Handshaking。可以形象的比喻为下面的对话 [Shake 1] 套接字A“你好套接字B我这里有数据要传送给你建立连接吧。”[Shake 2] 套接字B“好的我这边已准备就绪。”[Shake 3] 套接字A“谢谢你受理我的请求。”使用 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”字段看它的值是否为 10001如果是就说明连接建立成功。 接下来客户端会继续组建数据包并设置 ACK 标志位表示客户端正确接收了服务器发来的“确认包”。同时将刚才服务器发来的数据包序号2000加1得到 2001并用这个数字来填充“确认号Ack”字段。 客户端将数据包发出进入ESTABLISED状态表示连接已经成功建立。 4服务器端收到数据包检测到已经设置了 ACK 标志位就知道这是客户端发来的“确认包”。服务器会检测“确认号Ack”字段看它的值是否为 20001如果是就说明连接建立成功服务器进入ESTABLISED状态。 至此客户端和服务器都进入了ESTABLISED状态连接建立成功接下来就可以收发数据了。 三次握手的关键是要确认对方收到了自己的数据包这个目标就是通过“确认号Ack”字段实现的。计算机会记录下自己发送的数据包序号 Seq待收到对方的数据包后检测“确认号Ack”字段看Ack Seq 1是否成立如果成立说明对方正确收到了自己的数据包。 二、数据传输 建立连接后两台主机就可以相互传输数据了。如下图所示 上图给出了主机A分2次分2个数据包向主机B传递200字节的过程。首先主机A通过1个数据包发送100个字节的数据数据包的 Seq 号设置为 1200。主机B为了确认这一点向主机A发送 ACK 包并将 Ack 号设置为 1301。 为了保证数据准确到达目标机器在收到数据包包括SYN包、FIN包、普通数据包等包后必须立即回传ACK包这样发送方才能确认数据传输成功。 此时 Ack 号为 1301 而不是 1201原因在于 Ack 号的增量为传输的数据字节数。假设每次 Ack 号不加传输的字节数这样虽然可以确认数据包的传输但无法明确100字节全部正确传递还是丢失了一部分比如只传递了80字节。 因此按如下的公式确认 Ack 号Ack号 Seq号 传递的字节数 1。与三次握手协议相同最后加 1 是为了告诉对方要传递的 Seq 号。 下面分析传输过程中数据包丢失的情况如下图所示 上图表示通过 Seq 1301 数据包向主机B传递100字节的数据但中间发生了错误主机B未收到。经过一段时间后主机A仍未收到对于 Seq 1301 的ACK确认因此尝试重传数据。 为了完成数据包的重传TCP套接字每次发送数据包时都会启动定时器如果在一定时间内没有收到目标机器传回的 ACK 包那么定时器超时数据包会重传。 上图演示的是数据包丢失的情况也会有 ACK 包丢失的情况一样会重传。 重传超时时间RTO, Retransmission Time Out 这个值太大了会导致不必要的等待太小会导致不必要的重传理论上最好是网络 RTT 时间但又受制于网络距离与瞬态时延变化所以实际上使用自适应的动态算法例如 Jacobson 算法和 Karn 算法等来确定超时时间。 往返时间RTTRound-Trip Time表示从发送端发送数据开始到发送端收到来自接收端的 ACK 确认包接收端收到数据后便立即确认总共经历的时延。 重传次数 TCP数据包重传次数根据系统设置的不同而有所区别。有些系统一个数据包只会被重传3次如果重传3次后还未收到该数据包的 ACK 确认就不再尝试重传。但有些要求很高的业务系统会不断地重传丢失的数据包以尽最大可能保证业务数据的正常交互。 最后需要说明的是发送端只有在收到对方的 ACK 确认包后才会清空输出缓冲区中的数据。 三、断开连接【四次握手】 建立连接非常重要它是数据正确传输的前提断开连接同样重要它让计算机释放不再使用的资源。如果连接不能正常断开不仅会造成数据传输错误还会导致套接字不能关闭持续占用资源如果并发量高服务器压力堪忧。 建立连接需要三次握手断开连接需要四次握手可以形象的比喻为下面的对话 [Shake 1] 套接字A“任务处理完毕我希望断开连接。”[Shake 2] 套接字B“哦是吗请稍等我准备一下。”等待片刻后……[Shake 3] 套接字B“我准备好了可以断开连接了。”[Shake 4] 套接字A“好的谢谢合作。” 下图演示了客户端主动断开连接的场景 建立连接后客户端和服务器都处于ESTABLISED状态。这时客户端发起断开连接的请求 1) 客户端调用 close() 函数后向服务器发送 FIN 数据包进入FIN_WAIT_1状态。FIN 是 Finish 的缩写表示完成任务需要断开连接。 2) 服务器收到数据包后检测到设置了 FIN 标志位知道要断开连接于是向客户端发送“确认包”进入CLOSE_WAIT状态。 注意服务器收到请求后并不是立即断开连接而是先向客户端发送“确认包”告诉它我知道了我需要准备一下才能断开连接。 3) 客户端收到“确认包”后进入FIN_WAIT_2状态等待服务器准备完毕后再次发送数据包。 4) 等待片刻后服务器准备完毕可以断开连接于是再主动向客户端发送 FIN 包告诉它我准备好了断开连接吧。然后进入LAST_ACK状态。 5) 客户端收到服务器的 FIN 包后再向服务器发送 ACK 包告诉它你断开连接吧。然后进入TIME_WAIT状态。 6) 服务器收到客户端的 ACK 包后就断开连接关闭套接字进入CLOSED状态。 关于 TIME_WAIT 状态的说明 客户端最后一次发送 ACK包后进入 TIME_WAIT 状态而不是直接进入 CLOSED 状态关闭连接这是为什么呢 TCP 是面向连接的传输方式必须保证数据能够正确到达目标机器不能丢失或出错而网络是不稳定的随时可能会毁坏数据所以机器A每次向机器B发送数据包后都要求机器B”确认“回传ACK包告诉机器A我收到了这样机器A才能知道数据传送成功了。如果机器B没有回传ACK包机器A会重新发送直到机器B回传ACK包。 客户端最后一次向服务器回传ACK包时有可能会因为网络问题导致服务器收不到服务器会再次发送 FIN 包如果这时客户端完全关闭了连接那么服务器无论如何也收不到ACK包了所以客户端需要等待片刻、确认对方收到ACK包后才能进入CLOSED状态。那么要等待多久呢 数据包在网络中是有生存时间的超过这个时间还未到达目标主机就会被丢弃并通知源主机。这称为报文最大生存时间MSLMaximum Segment Lifetime。TIME_WAIT 要等待 2MSL 才会进入 CLOSED 状态。ACK 包到达服务器需要 MSL 时间服务器重传 FIN 包也需要 MSL 时间2MSL 是数据包往返的最大时间如果 2MSL 后还未收到服务器重传的 FIN 包就说明服务器已经收到了 ACK 包。