重庆网站建设帝玖科技,wordpress字不能,asp.net 公司网站,友の 连接#x1f431;作者#xff1a;一只大喵咪1201 #x1f431;专栏#xff1a;《网络》 #x1f525;格言#xff1a;你只管努力#xff0c;剩下的交给时间#xff01; 上篇文章对TCP可靠性机制讲解了一部分#xff0c;这篇文章接着继续讲解。
#x1f3a8;滑动窗口
在… 作者一只大喵咪1201 专栏《网络》 格言你只管努力剩下的交给时间 上篇文章对TCP可靠性机制讲解了一部分这篇文章接着继续讲解。
滑动窗口
在上篇文章中本喵讲解了TCP的确认应答机制 如上图所示主机A每发送一个数据段主机B都要给一个ACK确认应答 主机A收到ACK后再发送下一个数据段。
这样做有一个比较大的缺点, 就是性能较差数据段和数据段之间的发送就变成了串行的了尤其是数据往返的时间较长的时候效率更低。
为了提高效率采用一次发送多条数据的方式 如上图所示假设一个数据段的大小是1000字节主机A一次性发送四个数据段主机B一次给主机A四个ACK确认应答。
我们知道TCP协议中有超时重传机制如果主机A在一定的时间内没有收到主机B的确认应答那么就会触发超时重传再次将刚刚的数据段发送一遍。 所以数据段被发送出去以后不能立马清除需要再保存一段时间直到收到对端的确认应答这样是为了以防超时重传时再次发送。
那么在收到确认应答之前这些暂存的数据段是存放在哪里的呢答案是存放在发送缓冲区中。 如上图所示用户层将数据send到TCP的发送缓冲区发送缓冲区会存在大量的数据需要操作系统在合适的时候发出去由于TCP是面向字节流的所以势必不会一次性将发送缓冲区中的数据都发出去。
此时就会导致发送缓冲区中的数据有三种不同的状态同时也将发送缓冲区分成了三部分
已经发送并且收到ACK的数据。
如上图序号1所示这个区域的数据是已经发送了并且收到了ACK确认应答的数据说明这些数据对方完全收到了就没有存在的必要了所以新数据来了以后会将其覆盖。
已经发送但是没有收到ACK的数据。
如上图序号2所示这个区域的数据是已经发送了但是还没有收到ACK确认应答说明这部分数据对方可能没有收到也可能对方的ACK确认应答信号自己没有收到。
当触发超时重传后这部数据会被再次发送所以这部分数据不能被覆盖也不能被清除。 发送缓冲区中存放已经发送但是没有收到ACK数据的区域就是滑动窗口。 没有发送的数据。
如上如序号3所示这个区域的数据还没有发送更谈不上有没有ACK确认应答。 理解滑动窗口 如上图所示内核中的发送缓冲区可以看成是一个char outbuffer[N]数组存在win_start和win_end两个指针来标识滑动窗口的范围窗口滑动的本质就是数组下标的更新。
窗口最开始的大小是如何设定的 如上图红色框中所示在TCP协议的报头中有一个16位的窗口大小该值就是滑动窗口的大小。
在通信双方进行三次握手建立连接的过程中接收方将自己的接收能力告诉了发送方(起初是整个接收缓冲区的大小)也就是发送方在发送数据之前就确定了滑动窗口tcp_win的大小。
伪代码
win_start 0;
win_end win_start tcp_win;所以最开始滑动窗口的大小是从发送缓冲区起始位置开始的tcp_win个字节也就是对方通告给我的接收能力大小。
窗口一定是向右滑动吗会不会向左滑动 如上图所示假设现在滑动窗口的大小是4个数据段也就是4000个字节主机A先发送一个数据段(1001~2000)当主机B收到并且返回ACK时其中确认序号是2001。 确认序号表示发送端下次发送从这个序号的位置开始发送即可。 此时原本滑动窗口中的第一个数据段就变成了已经发送并且收到ACK的数据可以被覆盖了所以滑动窗口继续向右滑动第一个数据变成了原本的第二个数据段(2001~3000)。 由于数据的发送是从左到右的数据滑动窗口的滑动方向也是从左到右的不会向左滑动。
窗口大小会一直不变吗变的依据是什么 如上图所示假设发送缓冲区中一个黑色小框是一个数据段(大小是1000字节)在没有收到ACK前滑动窗口的大小是5个数据段。 收到ACK确认应答如上图所示确认序号是1001说明0~1000的数据段对方收到了下次从1001处开始发送所以滑动窗口的win_start向右滑动一个数据段指向1001处。
除此之外由于对方的接收缓冲区应用层没有读数据再加上又有新数据到来所以接收能力下降了应答信号中的16位窗口大小表示对方此时的接收能力是3000所以此时滑动窗口的大小就要发生变化。
win_end win_start tcp_win(3000)得到的就是新滑动窗口的结束位置此时滑动窗口相比原来变小了。 同样的也有可能对方在发送这次ACK确认应答的时候应用层恰好把整个接收缓冲区的数据都读走了此时接收能力就变大了确认应答信号中表示接收能力的16位窗口大小的值也比之前要大。
虽然win_start在向右移动但是win_end win_start tcp_win向右移动的更多所以此时滑动窗口和原来相比变的更大了。 滑动窗口变化大小的依据是对方接收能力的大小。 收到的确认应答不是滑动窗口最左边数据的确认应答而是中间的或者结尾的要滑动吗 发送数据的顺序是从左到右的理论上收到确认应答的顺序也是从左到右的收到不是最左边数据的确认应答的情况一定是丢包了。
丢包又有两种情况一种情况是发送的数据没有丢对方也收到了只是对方的确认应答信号丢了没有发送过来如下图 这种情况下部分ACK丢了并不要紧因为可以通过后续的ACK进行确认。 ACK确认序号该序号前的所有数据全部都收到了下次从该序号处开始发送。 如上图所示的情况中即使确认序号为1001的ACK丢了但是确认序号为2001的ACK没有丢。收到2001的ACK后就知道1~1000的数据也收到了滑动窗口可以直接向右移动两个数据段。
第二种情况就是发送的数据丢了对方没有收到如下图 如上图所示的情况中1~1000的数据段丢失之后发送端会一直收到确认序号为1001 的ACK就像是在提醒发送端 “我想要的是1001” 一样。
如果主机A连续三次收到了同样一个确认序号是1001的应答就会将包含1001的数据段(1001~2000)重新发送。
这个时候收到了1001~2000的数据段之后返回ACK的确认序号就是7001了。因为2001 - 7000其实之前就已经收到了并且被放到了接收端操作系统的内核接收缓冲区中。 这种重传机制被称为高速重发控制。也被叫做快重传。 滑动窗口必须要滑动吗会不会不动大小会不会变为0 滑动窗口是否滑动的依据是ACK中的确认序号。 当发生丢包等情况时滑动窗口是不会发生滑动的因为无法确定对方是否收到了发生的数据此时就会保持不动等待下一步策略执行。
当对方的接收缓冲区满了并且应用层没有读走数据时此时接收能力就是0所以ACK确认应答中的16为窗口大小也是0此时发生方滑动窗口大小就会变成0。
一直向右滑动吗如果空间不够了怎么办 滑动窗口如果一直向右滑动当发生缓冲区的空间不够时滑动窗口会不会越界呢答案是不会的。 因为发送缓冲区被操作系统组织成了环状结构所以滑动窗口无论怎么滑动都不会越界。
流量控制
接收端处理数据的速度是有限的如果发送端发的太快导致接收端的缓冲区被打满这个时候如果发送端继续发送就会造成丢包继而引起超时重传等等一系列连锁反应。 TCP支持根据接收端的接收能力来决定发送端的发送速度。这个机制就叫做流量控制(Flow Control)。 和滑动窗口中发送端知道接收端接收能力一样接收端将自己可以接收的缓冲区大小放入TCP首部中的16位窗口大小中再通过ACK端告诉发送端自己的接收能力。 窗口大小字段越大说明网络的吞吐量越高。 如上图所示主机A先发送了一个数据段得到的ACK中窗口大小是3000表示主机B有三个数据段的接收能力主机A下次发送数据时调整为一次发送三个数据段。
由于应用层读取数据缓慢等原因接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端发送端接受到这个窗口之后就会减慢自己的发送速度。
如果接收端缓冲区满了就会将窗口置为0这时发送方不再发送数据接收方也不再有ACK确认应答了。 发送端定期发送一个窗口探测数据段让接收端把窗口大小告诉发送端一但窗口值不再是0了发送端就可以额继续发送数据。否则通信就会暂停在这里了。 16位变量的最大值65535那么TCP窗口最大就是65535字节么?
实际上TCP首部40字节选项中还包含了一个窗口扩大因子M实际窗口大小是窗口字段的值左移M位。有兴趣的小伙伴自行研究首部中的选项。 在TCP首部的6个标志位中有一个PSH标志位该标志位的作用是催促接收端应用层尽快从接收缓冲区中将数据读走。
当接收端的接收能力快为0的时候在发送数据的时候可以将PSH置一接收方收到后发现PSH为一就会尽快将接收缓冲区中的数据拿走好尽快提高接收能力。
拥塞控制 如上图所示此时客户端要发送1000个数据段服务端接收到以后返回了ACK确认应答客户端根据确认序号发现丢了两个数据段直接使用快重传或者超时重传机制重新发送这两个数据段即可。
但是如果有999个数据段丢了服务端只收到一个数据段那么此时就是网络出问题了所以导致大量数据没有发出去。 少量的丢包仅仅是触发超时重传大量的丢包就认为网络拥塞。 客户端对于这999个发送失败的数据该如何处理呢
如果也进行重传那么就会让已经出现问题的网络雪上加霜。并且一个局域网中不止你一个客户端在发数据如果都采用这种重传方式那么整个网络中就会存在大量拥塞的数据使网络问题更加严重。 遇到网络拥塞时不能使用超时重传机制而应该使用拥塞控制的策略。 先不管拥塞控制是什么从TCP有这一机制就可以看出TCP的可靠性不仅仅考虑了双方主机的问题还考虑了路上网络的问题。 TCP引入慢启动机制来实现拥塞控制当发送网络拥塞后先发少量的数据探探路摸清当前的网络拥堵状态再决定按照多大的速度传输数据。 如上图所示当网络发生拥塞时主机A先发送一个数据段探探路如果收到这个数据段的ACK再将发送数据段个数增加。 此处引入一个拥塞窗口的概念。表示会产生网络拥塞的数据量。 在网络拥塞后第一次发送数据时将拥塞窗口的大小设置为1即一个数据段(1000)的大小每次收到一个ACK应答拥塞窗口加1。
再次发送时按照拥塞窗口的大小来发这一就会导致发送数据段的个数按照指数级来增长每次都是前一次的二倍。
之所以称这种方式是慢启动是因为最开始只发送一个数据段开始数据量的增长确实慢但是这是指数级增长后面数据量的增长就会越来越快。 慢启动的方式可以让发送方发送的数据量快速恢复到正常水平。这种快速恢复提高了网络通信的效率。 但是不能让这种增长速度不断增加下去否则就导致非常恐怖的数据量所以不能使拥塞窗口单纯的加倍。 再引入一个概念慢启动的阈值。 当以指数增长的拥塞窗口大小大于这个阈值的时候拥塞窗口不再按照指数级增长而是按照线性方式增长。 如上图所示便是拥塞窗口随传输轮次变化的示意图。
网络拥塞控制机制触发势必是因为已经发生了网络拥塞当上一次网络拥塞发生时阈值大小为16当发送方以慢启动方式开始发送数据后拥塞窗口按照指数级增长到16后变成了线性增长。
拥塞窗口线性增长到24以后再次发生了网络拥塞因为在这个过程中发送的数据量也在不断增加。此时将阈值更新为24的一半12。
然后发送方再以慢启动的方式发送数据拥塞窗口变成12以后再线性增长直到发送网络拥塞再次更新阈值。
如此反复不断更新阈值和拥塞窗口的最大值以便试探出当前网络状况下效率最高的数据传输量(阈值和拥塞窗口最大值不再变化)。 如果说在拥塞控制的过程中网络状况恢复了那么拥塞窗口就会一直增长下去发送数据量也在增长直到当前良好网络状况极限吗
接收方也是有接收能力限制的就算网络情况再好发送方也不以超出接收方接收能力数据量来通信。 发送方在每次发送数据的时候会将拥塞窗口的大小和接收端反馈接受能力大小作比较取较小值作为实际发送的数据量。滑动窗口大小 min(拥塞窗口大小对方接收能力大小)。 所以在网络状况良好的情况下发送方的滑动窗口大小取决于接收方的接收能力在网络拥塞的情况下发送方的滑动窗口大小取决于拥塞窗口的大小。 当TCP开始启动的时候慢启动的阈值等于滑动窗口的最大值如果网络状况良好那么拥塞窗口在增加到大于接收方的接收能力后变不再增加。
如果发送了网络拥塞后慢启动阈值就会变成原来的一半同时拥塞窗口置回1(最小值)逐渐找到最合适的拥塞窗口值和阈值。 当TCP通信开始后网络吞吐量会逐渐上升。随着网络发生拥堵吞吐量会立刻下降。 延迟应答
假设接收端缓冲区大小为1MB一次收到了500KB的数据如果立刻应答返回的窗口大小就是500KB。
但实际上可能接收端处理接收缓冲区中数据的速度很快, 10ms之内就把500KB数据从缓冲区消费掉了并且接收端处理速度还远没有达到自己的极限即使窗口再放大一些也能处理过来。
如果接收端稍微等一会再应答比如等待200ms再应答那么这个时候返回的窗口大小就是1MB了。 窗口越大网络吞吐量就越大传输效率就越高。我们的目标是在保证网络不拥塞的情况下尽量提高传输效率。 所有的数据报都采用延迟应答的方案吗肯定不是。
常用的方案有两种
数量限制每隔N个包就应答一次。时间限制超过最大延迟时间就应答一次。
具体的数量和超时时间依操作系统不同也有差异。一般N取2超时时间取200ms。 如上图所示延迟应答的最终表现就是隔几个数据段确认应答一次。
捎带应答
本喵再讲解协议格式的时候说协议首部中有两个序号是为了实现全双工也就是让应答和数据在一个数据段内。
即使有延迟应答但是很多情况下通信双方 “一发一收” 的虽然是收到多个数据段应答一次但是应答终究还是只有应答也就是只有确认序号和ACK标志位没有数据。
为了通信效率更高完全可以将确认应答和接收端要发送的数据放在一个数据段中发送出去发送端收到后既可以知道接收端收到了自己数据又收到了接收端发送的数据。 如上图所示确认应答信号中的确认序号和ACK标志位坐着数据的顺风车就发送出去了也就是在通信的过程中确认应答就被捎带给对方了。
面向字节流
在学C语言文件操作的时候就听到过面向字节流在学C的时候同样也听到过面向字节流在UDP和TCP的学习中更是多次见到面向字节流那么面向字节流到底是什么
创建一个TCP的socket时操作系统会同时在内核中创建一个发送缓冲区 和一个接收缓冲区。 应用层在调用write或者send时数据会先写入发送缓冲区中如果发送的字节数太长会被拆分成多个TCP的数据包发出。
如果发送的字节数太短就会先在缓冲区里等待等到缓冲区长度差不多了或者其他合适的时机发送出去。
接收数据的时候数据也是从网卡驱动程序到达内核的接收缓冲区然后应用层可以调用read或者recv从接收缓冲区拿数据。 由于缓冲区的存在TCP程序的读和写不需要一一匹配如写100个字节数据时可以调用一次write写100个字节也可以调用100次write每次写一个字节。读100个字节数据时也完全不需要考虑写的时候是怎么写的既可以一次read100个字节也可以一次read一个字节重复100次。 简而言之就是应用层和TCP层是完全独立的应用层写的时候不用考虑TCP层的缓冲区是否满应用层读的时候也不需要考虑缓冲区中的数据是怎么样的直接读就可以。 至于应用层写入或者读取的是否是一个完整的报文TCP层的缓冲区无法保证需要由用户层自己处理。
与面向字节流相对的就是面向用户数据报的UDPUDP协议用户层写入就是一个完整的报文然后给到UDP层UDP层并不会缓存而且增加相应的首部后直接发送出去发送的上一个完整的数据段。
接收方应用层读取的时候从接收缓存区中读取到的内容也是一个完整的数据段不能分多次读。
粘包问题 首先要明确粘包问题中的 “包”是指的应用层的数据包。 在TCP的协议头中没有如同UDP一样的 “报文长度” 这样的字段但是有一个32位序号的字段。站在传输层的角度TCP是一个一个数据段过来的按照序号排好序放在缓冲区中。
站在应用层的角度看到的只是一串连续的字节数据那么应用程序看到了这么一连串的字节数据就不知道从哪个部分开始到哪个部分是一个完整的应用层数据包此时应用层在读取数据的时候就会产生粘包问题可能读取的不是一个完整报文也可能是一个半报文等等情况。
解决这个问题归根到底就是要明确两个包之间的边界。
在之前的文章协议定制中采用的是TCP协议本喵在应用层读取接收缓冲区数据的时候通过用户层代码来保证每次读取到的是一个完整报文。 每个报文都有一个报头报头中的内容就是有效载荷的长度这是由本喵定义的用户层协议。
对于UDP协议来说就不存在粘包问题
如果还没有上层交付数据UDP的报文长度仍然在(在首部中)。同时UDP是一个一个把数据报交付给应用层就有很明确的数据边界。站在应用层的站在应用层的角度使用UDP的时候要么收到完整的UDP报文要么不收不会出现半个的情况。
TCP小结
TCP异常情况
进程终止进程终止会释放文件描述符仍然可以发送FIN和正常关闭没有什么区别。
一个进程终止后操作系统会释放这个进程的所有资源包括文件描述符表会自动调用close关闭对应的文件当TCP套接字被关闭时同样会发起四次挥手请求和正常关闭没有区别。
机器重启和进程终止的情况相同。
我们平时在关机的时候会提示有什么什么进程没有结束要我们强制结束这个时候也是在终止进程也会发起四次挥手请求。
机器掉电/网线断开此时就是一种真正异常情况。
发送端来不及发起四次挥手请求接收端认为连接还在一旦接收端有写入操作接收端发现连接已经不在了, 就会进行RST。 如上图所示首部的六个标志位中有一个RST标志位该标志位是用来请求重连的。当发送端在触发超时重发机制后仍然无法将数据发送到对方就会发送一个带有RST的数据段请求请求和对方重新发起三次握手建立连接。 即使没有写入操作TCP自己也内置了一个保活定时器会定期询问对方是否还在如果对方不在也会把连接释放。
另外应用层的某些协议也有一些这样的检测机制。例如HTTP长连接中也会定期检测对方的状态例如QQ在QQ断线之后也会定期尝试重新连接。 紧急指针
我们知道TCP协议中缓冲区的数据是按照顺序发送的接收缓冲区也是按照顺序来接收的但是如果我们想让某个数据插队呢让这个数据提前被接收端处理而不是按照顺序来此时就用到了紧急指针。 如上图所示六个标志位中的URG表示紧急指针是否有效16位紧急指针指向数据段中具体的某个数。 我们知道缓冲区本质上就是一个char类型的数组如上图所示而紧急指针是一个16位的变量所以它也是一个值范围是0~65535这个值其实就是缓冲区中有效载荷的偏移量。 一个紧急指针只能指向缓存区中一个数据。
当发送端想让某个数据插队时就将URG标志位置一然后让16位紧急指针指向这个紧急数据再将数据段发送出去。
当接收端收到数据段后发现URG置一了说明有紧急指针有数据需要优先处理然后再去16位紧急指针字段中拿到紧急数据的位置然后先读取这个紧急数据。 在之前我们使用send以及recv的时候最后一个参数是flags之前我们都是设为0的如果将其设置为MSG_OOB就表示发送或者接收的数据中存在紧急指针也就是将URG标志位置一了。
在发送或者接收的时候需要调用第二个参数是msg结构体指针的系统调用这个结构体中包含紧急指针的位置也就是16为紧急指针位段。
紧急指针的应用场景非常少一般应用在紧急获取对端状态的场景比如说客户端给服务端发送了很多条TCP请求服务端都没有给回应答客户端就可以发一个紧急数据确认服务端的状态。
TCP机制总结
TCP非常的复杂有众多的机制来保证它的可靠性和提高性能。
保证可靠性机制校验和序列号确认应答超时重传连接管理流量控制拥塞控制。
提高性能的机制滑动窗口快速重传延迟应答捎带应答。
其他机制超时重传定时器保活定时器TIME_WAIT定时器。
常见的基于TCP的应用协议HTTPHTTPSSSHTelientFTPSMTP以及前面本喵自己定制的应用层协议。
理解listen的第二个参数 前面本喵在创建TCP套接字的时候没有讲解listen系统调用的第二个参数backlog只是说随便设置一个数不要太大。 int backlog表示全连接长度。 如上图所示服务器进程中有一个listen状态的套接字用来监听还有多个recv后的套接字来进行真正的通信。
系统资源是有限的当用于通信的套接字数量达到限制以后系统就无法再维护更多套接字了新来的已经建立连接的套接字就会由于资源不足而被关闭。
当服务中某个或者几个用于通信的套接字使用完毕后就会释放出一部分系统资源此时也没有新的连接到来那么这部分系统资源就会空闲着。
所以TCP协议维护了一个全连接队列如上图蓝色部分所示这个队列中放的是处于等待状态的并且已经完成三次握手建立连接的套接字。
当系统资源不足时就在全连接队列中等待当系统资源有空余时全连接队列中的一个套接字就会被系统维护进行网络通信。 此时系统资源一空闲出来就会立刻被全连接队列中的套接字使用不会再出现空闲状态充分利用了系统资源提高了效率。 而listen的第二个参数backlog就是用来指定全连接队列的长度具体长度等于backlog 1 。 为什么说backlog值不能太大又不能没有呢
不能没有的原因就是本喵上面所说的要让系统资源一有空余就有新的套接字被系统维护提高系统资源利用率。
不能太大是因为维护全连接队列也要消耗系统资源如果全连接队列太长所耗费的资源完全够系统再维护一个套接字用来通信了属于是捡了芝麻丢了西瓜的做法。
除此之外全连接队列太长里面的套接字等待的时间也会很长此时又会触发超时重传机制等进而导致其他问题。 将之前写的TCP网络通信代码的backlog值设置为1也就是将listen的第二个参数设置为1此时全连接的长度为2。 将服务器运行起来此时服务器不会accept新的连接所以当新的连接到来时被会放入全连接队列中等待而设置的全连接队列长度是2所以最多放两个建立连接的套接字。 再创建两个Xshell窗口充当两个服务端使用telnet工具充当两个客户端与服务器进行连接。 使用netstat查看当前主机上和8080端口有关的网络进程如上图所示。
上面两行中表示两个客户端telnet它们的端口号分别是48406和48410对端都是服务器端口号是8080。
下面两行中表示服务器和两个客户端telnet第一行和第三行组成一对通信通信的端口号是48406 - 8080第二行和第四行组成一对通信通信的端口号是48410 - 8080。
此时全连接队列中放的就是端口号为48406和48410的两个客户端telnet进程。 全连接队列中的套接字状态是ESTABLISHED说明是完成了三次握手的已经和服务器建立了连接只是服务器没有进行维护进行通信。 此时再增加一个客户端如上图所示此时一共有3个telnet和服务器建立连接。 再次查看网络状态发现多了两个套接字上面红色框那行表示服务器下面红色框表示客户端。 服务器端套接字的状态是SYN_RECV。 客户端telnet套接字的状态是ESTABLISHED。 如上图所示再三次握手的过程中服务端第一次收到客户端的SYN请求以后服务端套接字的状态就变成了SYN_RECV只有服务端也发送SYNACK以后再收到客户端的ACK以后服务端才会变成ESTABLISHED表示连接建立。
而上面过程中第三个客户端发起连接请求后服务端套接字停在了SYN_RECV状态说明服务端已经收到了客户端的三次握手请求但是此时全连接队列已经满了服务端没有更多资源来维护这个套接字了所以不祥客户端发起SYN连接请求。 处于SYN_RECV状态的套接字叫做半连接状态。 对于半连接状态的套接字操作系统同样维护着一个半连接队列里面放着的是处于SYN_SNET和SYN_RECV等半连接状态的套接字。 但是可以看到客户端telnet的状态是ESTABLISHED也就是说客户端是认为建立了连接的但是服务端没有建立所以这次通信的建立是失败的。
当客户端发送数据的时候发现服务端没有对应的套接字就会发起RST请求重新建立连接。 等待一段时间后再次查看网络状态发现服务器端处于SYN_RECV状态的半连接套接字没有了而客户端的ESTABLISHED状态的套接字仍然存在。 处于半连接状态的套接字在一定时间内没有建立连接变成ESTABLISHED状态操作系统就会将这个套接字释放掉。 半链接队列用来保存处于SYN_SENT和SYN_RECV状态的套接字。 全连接队列用来保存处于ESTABLISHED状态的套接字但是应用层没有调用accept获取。 全连接队列满了的时候就无法继续让当前连接的状态进入ESTABLISH状态了。
总结
TCP协议到此就结束了可以看到它比起UDP来复杂很多因为TCP比UDP更加可靠可靠性的维护是需要付出代价的增加了序列化确认应答机制三次握手四次挥手机制等等很多机制。