当前位置: 首页 > 后端技术 > Java

网络是如何连接的:第2章(上)TCP连接的生命周期

时间:2023-04-02 10:42:58 Java

全书基于一个简单的场景:用户向浏览器输入一个URL,直到返回响应,生命周期的网络请求。全书分为六个部分:应用层客户端产生HTTP,委托操作系统的协议栈(TCP/IP模块)调用网卡驱动产生电信号。网卡如何到达路由器,用于通过路由器上网?web服务器之后,首先要通过防火墙,查看web服务器是如何接收数据的。第二章主要介绍操作系统中的协议栈和网卡如何向服务器发送应用消息:创建socket连接服务器发送和接收数据服务器断开并删除socketIP和以太网包收发operationsUDP收发数据操作本文介绍了1到4以及TCP模块的整个生命周期。主要观点如下:协议栈内部结构socket的实体是什么?有什么工具可以直接观察的吗?“连接”过程中发生了什么?发送和接收数据时的具体工作流程。“断开连接”期间发生了什么?0.概述在开始探索之前,我梳理了几个概念:协议栈的内部结构;套接字实体的生命周期TCP0.1协议栈内部结构所谓协议栈分为上下两部分,接收应用程序委托TCPUDP模块发送和接收数据。控制网络包发送的IP模块。IP模块包括ICMP协议和ARP协议。网卡驱动负责控制网卡硬件,用于监测发送网线中的光电信号。浏览器、邮件等一般应用程序一般使用TCPDNS查询等短期控制进行发送和接收。数据一般使用UDP0.2。socket的实体首先使用netstat来直观感受socket:协议栈中用来存放控制信息的内存空间控制信息:协议类型ip地址端口号status...在socket中它记录了双方的信息通信和通信状态,协议栈根据套接字中的控制信息工作。0.3TCP生命周期rfc793#section-3.2一个连接在它的生命周期中会经历一系列的状态。侦听、SYN-发送、SYN-接收、已建立、FIN-WAIT-1、FIN-WAIT-2、关闭等待、关闭、最后确认、时间等待、关闭。CLOSED是一个虚拟状态。在状态机上指示连接不存在。TCB:transmissioncontrolblock,通信控制块,即socket中存储的通信信息,详细解释三次握手,四次挥手TCP状态机:+--------+---------\主动打开|关闭|\----------+--------+<---------\\创建TCB|^\\sndSYN被动打开||关闭\\------------||----------\\创建TCB||删除TCB\\V|\\+---------+关闭|\|听|----------||+--------+删除TCB||接收SYN||发送||-----------||------|V+----------+sndSYN,ACK/\sndSYN+--------+||<---------------------------------->|||同步|接收SYN|同步||RCVD|<--------------------------------------------|已发送|||确认||||------------------------------------||+--------+rcvACKofSYN\/rcvSYN,ACK+--------+|--------------||----------|×||确认|VV|关闭+----------+|------|建立||sndFIN+----------+|关闭||rcv鳍V------||------+--------+sndFIN/\sndACK+--------+|鳍|<---------------------------------->|关闭||WAIT-1|--------------------|等待|+--------+接收文件FIN\+--------+|FIN的rcvACK------|关闭||--------------发送ACK|------|VxV和FINV+--------++--------++--------+|FINWAIT-2||结束||最后确认|+--------++--------++--------+|收到FIN的ACK|收到FIN的ACK||接收文件FIN--------------|超时=2MSL--------------||------xV----------xV\sndACK+--------+deleteTCB+--------+---------------------->|时间等待|-------------------->|关闭|+--------++--------+结合TCP生命周期分析连接创建、连接、发送和接收、断开过程1.创建socketintsocket(intaf,int类型,int协议);af:addressfamily,即IP地址的类型,常用的有AF_INET和AF_INET6AF_INET代表IPv4,如127.0.0.1AF_INET6代表IPv6,如1030::C9B4:FF12:48AA:1A2Btype:数据传输模式/socket类型,常用的有SOCK_STREAM、SOCK_STREAMSOCK_STREAM流格式socket/connection-orientedsocketSOCK_DGRAMdatagramsocket/connectionlesssocketprotocol:传输协议,常用的有IPPROTO_TCP和IPPTOTO_UDPIPPROTO_TCP:TCP传输协议IPPTOTO_UDP:UDP传输协议返回值:描述符,请参考socket()函数的详细说明,里面介绍了两个版本的linuxwindows下创建socket的流程从内存管理器申请一块内存-->malloc()初始化控制信息(协议类型ipaddressport)返回描述符给应用程序,用于唯一标识socket(控制信息),后续通信应用程序通过该描述符与协议栈进行交互。2.什么是连接服务器connectionintconnect(intsock,structsockaddr*serv_addr,socklen_taddrlen);sock套接字文件描述符serv_addraddressfamilyipportaddrlenserv_addrsize这个连接的上下文就是协议栈,因为对于网线来说,信号一直都在。在连接阶段,socket刚刚创建,协议栈并不知道通信对象是谁。在这个阶段,客户端会向服务器发送开始通信的请求,并相互交换控制信息。因此,将这个阶段称为准备阶段可能更为合适。连接时做什么:应用程序将服务器ip端口发送给协议栈。协议栈发起开始通信的请求。与控制信息交互。打开用于发送和接收数据的缓冲区。它负责保存控制信息的头部。通信操作中的控制信息分为两类:客户端和服务器相互通信时交换的控制消息。即TCP、IP、MAC等各种协议的头部。Header用于记录和交换控制信息,它保存在socket中,用于控制协议栈的运行。从应用程序传递并从通信对象接收的信息。对于socket中的控制信息,不同的协议栈有不同的实现,只要在通信时按规定生成协议头即可。TCP头信息:原文:https://www.rfc-editor.org/rfc/rfc793.html#section-3.1012301234567890123456789012345678901+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|源端口|目的港|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|序号|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|确认编号|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|资料||U|A|P|R|S|F|||抵消|保留|R|C|S|S|Y|I|窗口||||G|K|H|T|N|N||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|校验和|紧急指针|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|选项|填充|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|数据|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+控制信息:通信操作中的控制信息有两种:1.header中记录的信息2.socket中记录的信息(协议栈内存空间)可以用netstat查看socket使用wireshark(windows)或tcpdump(linux)查看协议头3.收发数据size_twrite(intfd,constvoid*buf,size_tnbytes);fd文件描述符write()函数将bufferbuf中的nbytes写入文件描述符fd对应的buffer中。成功则返回写入的字节数,失败则返回-1。应用程序调用协议栈后,不会立即发送。第一个存储的socket对应的发送接收缓冲区满足一定条件后才会发送:缓冲区数据长度大于等于MSS然后发送时间:协议内部有一个定时器,经过一定时间后,MTU=headersize(TCPIPheader,一般40字节)+MSSMTUMaximumTransmissionunitMSSMaximumSegmentSize最大段长度优先,大吞吐量优先,高延迟时间优先,低延迟,小吞吐量<--------MTU------>|IP头|TCP头|数据|<-MSS->写入缓冲区,读取缓冲区。类似的应用场景:数据库持久化机制。Reids、MySQL的异步刷取、kafkaproducer的异步发送等拆分更大的数据。如果请求的消息太大,它将被拆分成多个网络数据包。TCP头由TCP模块添加,IP头和MAC头由IP模块添加。ACK重传机制ACK重传机制在TCP头中有3个属性:SequencenumberACKnumber数据偏移量Sequencenumber:可以表示当前网络包数据的第一个字符在整个报文中的位置。数据偏移量:数据开始的位置。数据的长度可以通过TCP数据包的总长度和数据偏移来计算。ACK号:序号+数据长度。客户端发送数据后,服务器会返回ACK号。如果在一定时间内没有收到,就会重新发送。如果多次重发仍未收到ACK包,则向应用程序返回错误。由于TCP模块的重传功能,网卡路由器收到错误的网络包后会直接丢弃。调整ACK号的超时时间。当网络繁忙时,会发生拥塞,ACK的返回会很慢。如果超时时间短,频繁重试会加剧拥塞。TCP采用动态调整超时时间的方法。如果ACK号返回慢,则相应延长超时时间;如果ACK号返回很快,缩短超时时间。由于计算机的时间精度较低,太短的超时时间无法准确测量。基本上会调整到0.5秒到1秒。使用窗口管理ACK号。如果发送网络包后等待ACK号到达,再发送一个网络包。在等待ACK期间你不能做任何事情,这是浪费时间。为了提高效率,TCP使用滑动窗口来管理数据传输和ACK号。滑动窗口对应协议栈的收发缓冲区,对应TCP头的window属性。连接的两端会交换窗口大小(缓冲区的大小)。工作方式:接收方通知发送方剩余的窗口大小。发送方根据窗口大小连续发送网络数据包。接收方处理完缓冲区中的数据后,会告诉发送方缓冲区当前剩余的窗口大小。ACK和窗口的合并接收方什么时候向发送方发送ACK和窗口?首先,什么时候更新窗口大小?接收端从缓存中取出数据,传送给应用程序。接收方TCP连接阶段的交互窗口大小为2。当返回ACK时,数据到达接收方并存储在缓冲区中。您可以返回ACK编号。每收到一个网络包就发送ACK和window,会导致网络效率下降。因此,接收方在发送ACK和窗口更新时会等待一段时间,连续发送多个ACK号和窗口更新包时只需要发送最后一个ACK号或窗口大小即可。4.断开与服务器的连接并删除套接字。挥手四次后,连接进入TIME_WAIT状态。等待2MSL后,删除socket。什么是MSL?MSL:MaximumSegmentLifetime网络数据包的最长生命周期(参见RFC793)一个TCP段在网络系统中存在的时间定义为2分钟,这是一个工程经验值。Linux通常默认为30秒(如果端口数为6万,等待时间为30秒,那么在短连接的情况下,一个监听端口的最大qps为2000)。为什么要等2MSL发送一个网络包,然后返回一个ACK呢?为什么需要等待2MSL,然后删除socket?等待是为了防止误操作。举个简单的例子,客户端发送FIN,服务端返回ACK。服务器发送FIN,客户端返回。ACK如果客户端在第四步返回的ACK丢失,服务器会重新发送FIN。此时,客户端创建一个具有相同端口号的新套接字。收到服务器重发的FIN后,进入断开连接阶段。