ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TCP原理

TCP原理 1.报头TCP报头本质是结构体1.报头和有效载荷分离问题报头有一个“4位首部长度”字段[0,15]以4B为单位报头长度[0,50]在写入的时候报头长度/4读取的时候*4就是报头长度除去报头上下的就是有效载荷2.数据分用问题目的端口号UDP的报头包含报文长度字段减去报头长度就是有效载荷字段有效载荷字段为报文的完整性和边界负责TCP报文包含数据段但是TCP不为报文的完整性和边界负责只保证端到端的字节流传输至于一个报文包含的数据是否语意完整上层负责TCP报头长度为20nn是选项字段一般建立连接和少部分通信会用到选项字段所以报头的范围是[20,60]四字节首部长度[5,15]TCP为可靠性协议但是该可靠是指“对于发出去数据状态的确认”发出去的数据有没有被对方接收要知道状态对比UDP发出去了之后无论被丢弃还是对方收到了我不care这个丢包重传的时间段不能太长太长导致丢的报文一直不能被重传耽误进度太短导致一直进行重传比如RTT应答还在路上就进行重发会导致发送方大量时间浪费在重发上接收方重复收到报文进行去重丢弃这些无意义的工作可以避免的用来做更重要的事情随着网络变化比如网络好了RTT小丢包重传的时间段就小一些但是RTT如果网络差RTT大丢包重传的时间就长一些有两种情况一种是收到了应答再发下一个报文串行慢第二种就是接连发多个报文这样等待应答的期间也可以发报文效率高现在采用的模式对比UDP不保证收到报文和发送报文顺序的一致性乱序也就是不可靠TCP报头字段有序号接收方收到之后就可以知根据序号对收到的报文进行排序保证按序到达序号也可以去重比如发送序号w为300的报文应答丢了但其实对方已经收到了但是A没有收到应答认为丢包重传B收到发现之前已经接受过序号为300的报文就把之前收到的丢弃替换为新的确认序号对收到报文的确认表示该序号之前的报文都收到了收到的连续最大报文序号1有效减少报文重发次数比如下面序号300报文的应答报文丢失了但是序号400报文的应答报文ack_seq401说明序号401之前的报文都收到了也就是说序号300的报文收到了即使序号300报文本身的应答报文丢失也不会影响发送方对于序号300报文已被接收状态的确认发送的始终都是TCP报文这一点在后续TCP三次握手示意图一般都是SYNACK但其实传输的并不是单个字符为什么有序号确认序号在发送的时候是序号应答的时候是确认序号共用一个省内存、带宽这是因为A给B发数据B做应答的时候也可以给A发数据也就是捎带应答B给A发数据的时候顺手把应答带回去发送数据和确认同时进行序号确认序号-去重按序到达捎带应答超时重传根据应答分析丢的是哪一个报文根据序号重传流量控制 可靠性效率如果A发送过快B来不及收就丢弃了但是报文的发送需要带宽等资源如果因为B来不及收丢弃着实浪费那B就要告诉A自己的接收能力B如何衡量自己的接受能力TCP支持全双工在内核维护发送缓冲区和接收缓冲区接收缓冲区剩余空间衡量接收能力接收方如何告知发送方自己的接受能力报文有一个字段是窗口大小B在做应答的时候可以把自己剩余缓冲区大小填到该字段发给AA根据B的剩余缓冲区大小决定发送速度如果大就可以发快一点小就慢一点如果ACK报文段的16位窗口大小为0但是服务端后续应用层取走接收缓冲区的数据处理窗口大小变大那客户端怎么知道呢客户端可以向服务器发报头不发数据收到服务器的应答就可以确认窗口或者服务器主动给客户端发报头告知客户端自己的窗口更新了接下来看六个标志位-区分报文类型建立连接应答报文数据报文断开连接URG(urgent)紧急指针是否有效ACK(acknowledgment)确认号是否有效PSH(push)提示接收端应用程序立刻把从TCP缓冲区把数据读走RST(reset)对方要求重新建立连接我们把携带RST标识的称为复位报文段SYN(synchronize)请求建立连接我们把携带SYN标识的称为同步报文段FIN(finish)通知对方本端要关闭了我们称携带FIN标识的为结束报文段ACK为1应答报文捎带应答绝大多数报文ACK1SYN1连接建立的请求报文连接究竟是什么服务器端肯定存在大量客户端发起的连接客户端也会向多个服务器发起请求服务器端和客户端都要对连接做管理先描述再组织inet_connection_sock就是对连接的描述管理可以使用链表等数据结构建立连接就是在本地建立结构体变量插入到数据结构建立连接有空间成本和时间成本因为肯定要维护连接内部的值比如建立断开等当然最常见的就是三次握手一般客户端请求服务器都会ACK并且也发起建立连接的请求服务器顾名思义提供服务四次挥手RSTPSH: 全称push提示接收端应用程序立刻把数据从接收缓冲区读走举一个极端的例子如果client给server发数据server的ACK报文的报头16位窗口大小值为0但是client要发数据就不断的给server发报头不带数据得到的窗口大小总是0结果client一直发不了数据就断开连接所以增加PSH标志位如果为1就是告诉对端应用程序赶紧把接收缓冲区的数据读走那内核是怎么做的呢把目的端口对应的进程从等待队列放到运行队列而之后进程是否进行read这不是内核能决定的大多数情况下SSH报文的PSH为1URG报头字段紧急指针是否有效16位紧急指针标识哪些数据是紧急数据TCP全称是transer control protocol 传输控制协议应用层调用read把数据写到传输层也就是内核开辟的缓冲区就返回至于发送缓冲区的数据什么时候发发多少出错了怎么办就是TCP的事情我们可以把发送缓冲区看作数组元素类型为char面向字节流双方规定从1开始报文段的序号假设从1开始一般是随机值为了防止被恶意盗取、篡改等假设第一次发送1000字节报文段序号为1等到第二次发送的时候报文段序号为1001紧急指针在报文段中的偏移量为500也就是从1001开始的500个字节是紧急数据TCP按序到达即使1001-1500是紧急数据但是TCP接收也是按序接收先交付1-1000但是通知应用层有紧急数据可以单独先读取紧急数据在TCP的recv读取接口中可以使用MSG_OOB字段单独读取紧急数据一般只读一个字节1001500-11500也就是该报文段的偏移量500字节的数据举个例子比如百度网盘上传文件要终止此时这个终止就是紧急数据举个例子实际上用的不是这个现在一般都弃用了一般采用两个连接来实现accept是拿到tcp建立好的连接分配文件描述符用于应用层向网络里写入和从网络里读取的途径2.连接管理2.1 三次握手 四次挥手Q1: 为什么是三次握手三次握手保证收发应用层数据之前建立信道会遇到的阻碍是双方主机可能有一方不愿意通信或者网络状况不好那么三次握手就要排除这些情况一般是服务端向客户端发起建立连接的请求服务器顾名思义给客户提供服务自然无条件接受来自客户端的请求除非是恶意用户客户端首先给服务器发送SYN报文表示请求建立连接服务器做应答同时发送SYN表示我同意建立连接我也请求和你建立连接客户端应答同意建立连接所以双方主机在通信意愿上没有障碍接着客户端发SYN收ACKSYN说明C-S发和收都是没有问题的服务器发SYNACK收到ACK说明S-C发和收也没有问题至此三次握手完成了确认网络情况和双方通信意愿的确认为什么不是两次握手如果只有前两次S只收到了SYN数据报S没有收到应答S不知道发出去的报文对方有没有收到不确定S-C的发送信道是否通畅如果3次比如SYN和ACK分开这样导致成本更高所以三次握手以最小代价验证网络通畅和双方通信意愿全双工通信三次握手每一次都是从发出开始算的由双方TCP层自主完成2.2 测试backlog没有accept连接可以建立成功连接建立是tcp的事和应用层无关SYN_SENT接收端维持的暂时没有accept到应用层的连接个数是有限的backlog1也就是全连接队列三次握手成功的缓存结果为什么维持全连接队列因为一些连接来不及accept到应用层但之后应用层可能会accept这些连接到应用层所以需要暂时维持到全连接队列为了保证服务器的满载率队列不能太短这样很多连接就被丢弃或者赶不上应用层accept的速度导致不满载太长维护连接是需要内存算力维护相关属性值太长用不了就会浪费资源CLOSE_WAITFIN_WAIT2TIME_WAIT进入TIME_WAIT不算连接关闭因为TIME_WAIT本就是维护套接字struct sock内的一个属性值说明这些管理连接的结构体还在并且ip和port还在占用引出了地址复用并且如果服务器出现了大量的CLOSE_WAIT说明出现了bug服务器可能没有及时关闭对应的fdC端已经断开连接了结果S端还维护着连接正常应该是虽然S端在C端断开连接后可能还要发数据维持着连接那也是少部分因为发完就会断开连接4次挥手之后主动断开连接的一方进入TIME_WAIT被动断开连接的一方立即释放连接为什么为什么要进入TIME_WAIT进入TIME_WAIT后等待2MSL时间进入CLOSED状态MSL(Maximum Segment Lifetime)最大报文生存时间因为一方面确保双方4次挥手都尽可能正确完成对方收到ACK认为连接断开但是ACK可能丢失那么如果丢失对方超时重传FIN如果在发出ACK之后进入CLOSED结果ACK丢失对方没有收到重传FIN的时候连接已经断开收不到对方的ACK对方的连接就会异常另一方面让陈旧报文在网络中尽可能消散因为在断开连接发出去的报文可能因为网络拥塞在某个路由器处排队如果不做等待直接进入CLOSED如果立刻重新发起连接建立连接之前堆积在网络中的报文可能误被对方认为是新的报文比如新的连接复用之前的端口而新的ISN比如是998之前在网络中陈旧报文是1000新的报文发送过程中也发了1000这时候接收方收到旧的1000可能会把陈旧报文交到应用层造成混乱而2MSL是两倍的报文在网络中最大的生存时间可以让在网络中挤压的报文都消亡要么被递达要么被路由器因超时丢弃可以查到MSL3.滑动窗口3.1 无丢包分析三次握手完成第一次发送数据滑动窗口多大因为在三次握手的时候交换过报头所以从ACK应答报文可以得到对端的16位滑动窗口大小一个报文发出去之后收到应答之前应该被发送方OS丢弃吗UDP可以但是TCP不可以那么要临时保存起来保存在哪里根据对端接受能力调整数据发送速率也就是流量控制通过滑动窗口但本质上接收和发送缓冲区是sk_buff维护的队列滑动窗口会变小吗会如果应用层没有及时读取接收缓冲区的数据会不变吗会如果应用层立即读取收到的数据会变大吗会如果本来接收缓冲区是4000但是收到1000应用层一下读走了4000那接收缓冲区就是700016位窗口大小是对端接收缓冲区剩余空间大小去局域对端接收缓冲区大小和应用层读取数据的速度滑动窗口会向左滑动吗首先看start_win因为ack_seqstart_win所以start_win不会递减接着是end_winend_winstart_winack_win-1假设刚开始start_win1001ack_win4000end_win就是5000如果接收方收到并应答2001start_win变为2001ack_win要么是4000-10003000要么就是应用层读取速度快ack_win3000end_win5000也就是说end_win不会递减因此滑动窗口不会左移3.2 丢包分析最左侧报文应答丢失上面收到重传的报文之后根据报文段的序号进行去重保留最新的丢弃之前的数据丢失数据丢失一样是没有应答和上面一样如果后续发的报文不足三个没有触发快重传超时没有收到ack也是重传也可以看出来ack_seq的设计为ack_seq之前的报文全部收到那么start_win就可以更新为ack_seq保证start_win左侧的报文都已经被接收端收到也引出快重传机制回到上面的问题发送但没有应答的数据保存在哪里滑动窗口内部滑动窗口左侧的报文都是已经应答过的可以丢弃实际应用就是可以被覆盖写非最左侧报文段的丢失还有一个问题发送和接收缓冲区被看作数组本质是环形数组start_win和end_win计算的时候都会模上缓冲区的长度底层是队列模拟感觉刷题会遇到滑动窗口环形队列这种题不是没有原因的底层应用就是这些问题为什么接收方的16位窗口大小为4000但每次报文只能发1000的有效载荷和MAC帧有关4.拥塞控制上面提到的策略是端到端传输的策略那网络情况在通信过程中也是要考虑的如果发送1000个报文丢了1个是正常的但是如果丢900个就是网络拥塞了重传没太大意义因为重传很大可能也会丢因为网络中有很多主机都重传原来的拥塞就会加倍丢那么多可能有很多报文在路由器排队已经拥塞了再重传只会加重拥塞所以要进行拥塞控制实际上一般丢包率1.5%是正常2%是拥堵3%数非常拥塞此处假设接受能力无限大简化问题但实际上接受能力肯定是上限我们可以头脑风暴一下如果网络中的报文已经超过承受限制了这个时候最好的做法就是别发了给网络一点缓冲时间让现有的报文处理了再来新的报文但这样做得话有些极端我们可以折中一下边试探边发送我先发一个报文如果收到应答说明网络可以承受一个报文接着发两个四个以此类推那如果一个报文都超时了那说明网络一个报文都扛不住别说2个了就重传等着网络好吧采用慢启动机制发送报文为2^ 0, 收到应答就发2 ^ 1 收到应答就发2^2以此类推刚开始以指数级增长恢复快这样的好处是刚开始发的少网络入口流量出口流量网络压力减小拥有缓冲时间解决拥塞并且边试探边发根据网络情况决定发的速率到达ssthresh之后线性增长拥塞窗口每次1如果再次拥塞拥塞窗口为1ssthresh更新为拥塞窗口/2在可靠性和效率中寻找平衡点拥塞窗口衡量网络接受能力的指标发送数据超过该窗口可能发生网络拥塞滑动窗口min(16位窗口大小拥塞窗口)网络是变化的那么发生拥堵的上限是变化的拥塞窗口肯定是变化的那TCP如何知道拥塞窗口大小TCP不知道也是边尝试试探当前网络的接收能力边发送5.应答机制5.1 延迟应答顾名思义在收到报文之后不立刻做应答而是等待一段时间再应答好处是什么呢可以减少应答报文数量比如1-1000的报文到来后不立即应答接着应用层可能取走数据那ACK的16位窗口大小就会更大如果这个时间内1001-2000的报文到了那发送ACK的ack_seq就是2001好处是本来需要发两个ACK报文一个ack_seq1001一个ack_seq2001现在只需要发一个ack_seq2001减少发送报文数量减少网络带宽和流量同时由于应用层可能在延迟应答的时间内取走数据可以返回更大的16位接收窗口发送方可以同时发送更多数据提高效率一般延迟的时间是500ms或者每N个报文一次应答N一般为25.2 捎带应答前面已经提过了因为接收方也要给发送方发送数据就把发送的数据放在接收方给发送方的应答中这样本来发两次只需要一次发送就能搞定适用于双方互相通信的场景提高报文发送速率也因此几乎所有报文的ACK1因为第三次握手的时候发起连接的一方认为连接已经建立成功所以第三次握手可以捎带应答携带数据但是前两次不行被动接受连接的一方发出SYN的时候不认为连接已经建立好了6.连接异常网络两台主机通信本质是两台主机上的两个进程通信如果发送方或者接收方进程终止怎么办其实进程终止会由OS进行进程管理进程打开的文件生命周期随进程进程终止OS要释放进程打开的文件TCP层也是OS就会释放对应的文件描述符发送FIN报文进行连接断开也就是连接时双方OS来断开如果重启呢我们在关闭windows电脑的时候一般显示是否要关闭一些应用程序如果选择是OS就会终止进程那么又回到上面的情况那如果硬件出问题了呢断电网线拔了OS检测到网卡异常内部不再维护连接对端呢对端TCP层会有一个保活定时器引入心跳机制如果双方不发数据就每隔比如5s给对方发送一次报文如果收到应答就更新活跃时间如果没有收到应答重发若干次如果还没有收到关闭连接但一般使用的是应用层来进行连接的关闭因为传输层一般维持几十分钟没有必要而且传输层没有办法知道用户是否有通信意愿的所以应用层一般会有一个比如线程在双方正常通信的时候不工作如果双方不通信就每隔一段时间给对方发送报文如果收到对方的保活报文就维持连接但一般维持个5分钟或者其它时间就断开了比如客户端要知道服务器端是否正常业务是否正常使用echo sever就是心跳检测对服务器端进行保活假设服务器重启了客户端还认为连接在服务器端已经没有连接了客户端给服务器发数据服务器发现没有连接就应答的RST1重置连接问收到TCP报文因为首部固定长度20B提取前20B有首部长度字段拿到之后首部和有效载荷分离有效载荷写到接受缓冲区7.粘包问题一般应用层解决可以使用固定长度比如发送固定长度字节的报文少了填充多了分开发可以使用自描述字段比如UDP就是首部固定长度报文长度区分报文边界或者特殊字符比如HTTP报头和有效载荷使用空行分割报头有Content-Length字段获取有效载荷长度如果UDP想实现可靠性因为有些应用场景对可靠性要求不像TCP那么高但有一定的可靠性需求可以按需在应用层仿照TCP可靠性策略设计如果应用层希望报文按序到达那就可以引入序号如果不能忍受丢包就确认应答或者重传三次握手底层创建的是struct tcp_sockaccept就是建立struct filestruct tcp_socket返回文件描述符端口号是保留给常用的服务器应用程序的也被称为熟知端口其范围是 A.01024B.01023C.11024D.11023B下列TCP端口号中不属于熟知端口号的是A.21B.23C.80D.3210D【多选题】FTP服务的控制端口与数据端口默认是A.20B.21C.22D.23AB关于UDP的说法正确的是A.UDP的包大小没有限制B.UDP不会进行错误重传C.UDP跟TCP一样提供可靠的数据报协议D.UDP有简单的流控制B于TCP和UDP说法错误的是A.TCP是面向连接的协议UDP是无连接的协议B.TCP和UDP消息到达网络另一端都是有序的C.TCP速度比较慢UDP速度比较快D.UDP没有流量控制和拥塞控制B主机甲向主机乙发送一个(SYN1,seq11220)的TCP段,期望与主机乙建立TCP连接,若主机乙接受该连接请求,则主机乙向主机甲发送的正确的TCP段应该是A.(SYN1,ACK1,seq11220,ack11220)B.(SYN1,ACK1,seq11221,ack11221)C.(SYN0,ACK0,seq11221,ack11221)D.(SYN0,ACK1,seq11220,ack11220)B下列哪项最恰当地描述了建立TCP连接时“第一次握手”所做的工作 ( )A.“连接发起方”向“接收方”发送一个SYN-ACK段B.“接收方”向“连接发起方”发送一个SYN-ACK段C.“连接发起方”向目标主机的TCP进程发送一个SYN段D.“接收方”向源主机得到TCP进程发送一个SYN段作为应答CTCP 三次握手的过程accept 发生在三次握手哪个阶段A.第一次握手B.第二次握手C.第三次握手D.三次握手后D【多选题】客户端主动断开TCP连接的时候以下四次挥手过程中状态变迁表述正确的是A.Client发送一个FIN用来关闭Client到Server之间的数据传输Client进入FIN_WAIT1状态B.Server收到了来自Client的FIN包发送一个ack给client进入CLOSE_WAIT状态C.Server发送一个FIN用来关闭Server到Client之间的数据传输Server进入LAST_ACK状态D.Client收到FIN包之后Client发送一个ACK给Server, 紧接着进入TIME_WAIT状态Server收到ack后进入CLOSED状态ABCD【多选题】客户端主动断开TCP连接的时候以下“四次挥手”过程中表述错误的是A.当Client收到Server的ACK包之后Client状态变成FIN_WAIT2状态B.当Server发送FIN包到Client之后Client需要等待1MSL状态才从TIME_WAIT状态变成CLOSED状态C.Server端出现大量的CLOSE_WAIT状态是由于Client没有及时的关闭连接D.“四次挥手”是完全没有必要的“三次挥手”就可以了BCDTCP使用滑动窗口进行流量控制流量控制实际上是对 的控制A.发送方数据流量B.接收方数据流量C.发送、接收方数据流量D.链路上任意两节点间的数据流量ATCP/IP 模型中哪一层处理传输的可靠性、流量控制和错误控制A.应用层ApplicationB. 传输层TransportC.互联网络层InternetD.网络访问层Network AccessB以下关于TCP可靠性说法错误的是A.TCP能保证数据的正确性无差错、不丢失、不重复、并且按序达到B.三次握手和四次挥手也是TCP可靠性的保证C.TCP的流量控制也是TCP可靠性的保证D.以上说法都是不正确的D主机甲和主机乙新建一个TCP 连接甲的拥塞控制初始阈值为 32KB甲向乙始终以 MSS1KB 大小的段发送数据 并一直有数据发送乙为该连接分配 16KB 接收缓存并对每个数据段进行确认忽略段传输延迟。若乙收到的数据全 部存入缓存不被取走则甲从连接建立成功时刻起未发送超时 的情况下经过 4 个 RTT 后甲的发送窗口是 A.1KBB.8KBC.16KBD.32KBA在TCP报文段中接收窗口receive window字段用于( )A.可靠数据传输B.延迟保证C.流量控制D.拥塞控制C【多选题】TCP 状态变迁中存在 TIME_WAIT 状态请问以下正确的描述是A.TIME_WAIT 状态可以帮助 TCP 的全双工连接可靠释放B.TIME_WAIT 状态是 TCP 是三次握手过程中的状态C.TIME_WAIT 状态是为了保证重新生成的 socket 不受之前延迟报文的影响D.TIME_WAIT 状态是为了让旧数据包消失在网络中ACDTCP 连接有多重状态如何在系统中查看某个连接的状态A.pingB.netstatC.ifconfigD.tracerouteBTCP主动关闭一方进入最后的一个状态是A.CLOSE_WAITB.SYN_SENTC.TIME_WAITD.LAST_ACKC以下不属于tcp连接断开的状态是A.TIME_WAITB.FIN_WAIT_1C.SYNC_SENTD.FIN_WAIT_2CTCP协议在建立连接的过程中可能处于不同的状态用netstat命令显示出TCP连接的状态为SYN_SEND则这个连接正处于A.监听对方的建立连接请求B.已主动发出连接建立请求C.等待对方的连接释放请求D.收到对方的连接建立请求B【多选题】以下哪种情况下会可能会触发TCP粘包A.应用程序写入数据小于套接字缓冲区大小网卡将应用多次写入的数据发送到网络上这将会发生粘包B.应用程序写入的数据大于套接字缓冲区大小这将会发生粘包C.接收方不及时读取套接字缓冲区数据这将发生粘包D.当应用程序数据长度-TCP头部长度MSS的时候将发生粘包AC以下哪种描述不可以缓解TCP粘包问题A.使用带消息头的协议、消息头存储消息开始标识及消息长度信息服务端获取消息头的时候解析出消息长度然后向后读取该长度的内容B.设置定长消息服务端每次读取既定长度的内容作为一条完整消息当消息不够长时空位补上固定字符C.设置消息边界服务端从网络流中按消息编辑分离出消息内容一般使用‘\r\n’D.以上的说法中A和B可以缓解C不行D以下关于TCP粘包说法不正确的是A.可以使用短连接来解决TCP粘包的问题B.关闭nagle算法一定能够解决TCP粘包问题C.nagle算法其中之一的规则为如果该包含有FIN则允许发送D.nagle算法可以很大程度的利用网络带宽Bnagle算法是要么数据攒够1个MSS或者发的数据都应答才会发数据TCP数据包里的出现什么标志位表示连接被异常终止或被拒绝的异常请求A.FIN/ACKB.RST/ACKC.SYND.ACKB以下情况下不一定出现TCP分节RST的情况是A.服务器端端口未打开而客户端来连接时B.SO_RCVTIMEO选项设置了超时时间并超时C.服务器主机崩溃后重启D.在一个已关闭的socket上收到数据CB是recv的参数以下关于TCP连接异常描述错误的是A.若向已经接收到RST的sock继续写入数据则内核会向该进程发送一个SIGPIPE信号该信号默认为中止进程。且写操作返回错误EPIPEB.服务器主机崩溃可能会导致read返回ETIMEOUTC.服务器主机崩溃后重启后客户端发送送数据时不会受到RST报文D.服务器主机主动关机会导致连接发生异常Cint listen(SOCKET s, int backlog);该函数中第二个参数的含义是A.是否打开log信息B.是否打开后台log信息C.后台等待连接队列的最大限制值D.后台等待连接队列的最小限制值C下面关于int listen(SOCKET s, int backlog)函数说法不正确的是A.listen函数是系统调用B.listen函数是库函数C.backlog维护complete connection queue的长度D.backlog维护incomplete connection queue的长度BD
返回列表