当前位置: 首页 > news >正文

wordpress如何写网站搜狗网站

wordpress如何写网站,搜狗网站,网页游戏开服表弹窗,网站开发从什么学起目录 重新认识端口号 端口号划分 netstat pidof UDP协议 UDP的特点 面向数据报 UDP的缓冲区 全双工和半双工 TCP协议 TCP的特点 TCP报头分析 源端口#xff0c;目标端口#xff0c;数据偏移(报文首部长度) 序号 确认号 窗口 6个标志位 ACK SYN …目录 重新认识端口号 端口号划分 netstat pidof  UDP协议 UDP的特点 面向数据报  UDP的缓冲区  全双工和半双工 TCP协议 TCP的特点  TCP报头分析  源端口目标端口数据偏移(报文首部长度) 序号  确认号  窗口 6个标志位  ACK SYN  RST  PSH URG FIN TCP的三种机制 确认应答机制 超时重传机制  连接管理机制 两种等待状态  TIME_WAIT CLOSED_WAIT  滑动窗口 滑动窗口的丢包处理 中间报文的响应丢失 中间报文的请求丢失  流量控制 拥塞控制 延时应答 捎带应答  面向字节流和粘包 TCP异常 TCP与UDP对比 listen的第二个参数  前几期我们已经学习完了基于应用层的Http和Https协议本期我们将继续学习网络通信协议栈中的应用层下一层传输层的重要协议。 重新认识端口号 通过前几期的学习我们知道公网IP可以唯一确认计算机网络中的一台主机而一个端口号可以唯一确认一台主机上的唯一一个进程所以一个IP端口号可以唯一的确认一台主机上的一个进程。我们又把IP端口号统称为socket我们又称网络通信的本质其实就是进程间通信。  端口号端口号(Port)标识了一个主机上进行通信的不同的应用程序端口号是一个16位数字。 基于上述知识我们再来回顾两个问题一个进程可以绑定多个端口号吗一个端口号可以绑定多个进程吗 此时这个问题的答案就显而易见了因为一个端口号唯一的确认一台主机上的一个进程所以一个端口号只能绑定一个进程而一个进程是可以绑定多个端口号的因为进程是无限的而端口号是有限的。  端口号划分 因为端口号是16位的数字表示的整数的范围是0~65535操作系统会对这些端口号进行划分。  0~1023知名端口号HTTP,FTP,SSH这些广泛使用的协议的端口号所处的范围它们的端口号是固定的。1024~65535操作系统动态分配的端口号,如我们之前写的client端套接字代码不用绑定IP端口号这是在client端发送数据时操作系统自动为其绑定的。 常见的知名端口号如下。 ssh服务器22号端口。ftp服务器21号端口。telnet服务器23号端口。http服务器80端口。https服务器443端口。  注意以上服务器端口是固定的不会进行变化的。 netstat netstat可以搭配选项查看网络状态。 n 不显示别名将能显示数字的全部转化成数字l 仅列出有在 Listen (监听) 的服务状态p 显示建立相关链接的程序名t (tcp)仅显示tcp相关选项u (udp)仅显示udp相关选项a (all)显示于显示当前系统的所有网络连接、监听端口以及相关的网络统计信息。 pidof  pidof用于查看进程id。  之前我们也学习过使用ps -ajx的指令来查看特定进程的id但是今天学习的pidof查看进程id更加方便。 使用ps -ajx查看mysqld进程id。 使用pidof mysqld查看进程id。  UDP协议 UDP协议使我们在网络协议栈的传输层中学习的第一个协议。 UDP报文如下图所示。 在日后学习协议时我们通常会抛出两个问题。 UDP报文是如何实现封装和解包的UDP报文是如何实现分用的 我们先来回答第一个问题UDP报文通过对有效载荷添加8字节报头进行封装在进行解包时因为UDP报文中有一个16位UDP长度我们规定一个长度的基本单位是一个字节这个16位UDP长度所代表的字节数及时UDP有效载荷和报头总共的大小所以可以根据16位UDP长度计算出报头和有效载荷即报文的总大小然后用报文的总大小减去UDP8字节的报头就可以得到有效载荷即数据的大小实现报文的解包。 再来回答第二个问题在UDP报文中有16位源端口号和16位目的端口号分别表示当前报文从哪里来到哪里去所以可以根据16位目的端口号实现报文的分用。 UDP的特点 无连接只需要知道对端的IP端口号就可以进行传输不需要建立连接。 不可靠没有确认机制就是传送的一方不知道自己传送的数据是否被被对端接收到没有重传机制如果当前报文传送失败当前报文再也不会进行传送。如果传送报文时因为网络故障无法传送到对端UDP也不会给应用层传送任何错误信息。 面向数据报不能灵活的控制读写数据的次数和数量。 面向数据报  在上一标题UDP的特点中我们提出了UDP是一个面向数据报的协议那么什么是面向数据报呢 面向数据报其实就是应用层交给UDP多长的报文那么UDP在进行发送的时候既不会进行报文的拆分也不会进行报文的合并。所以也就意味着当发应用层给发送端一次发送了100字节的数据那么接收端接收到数据之后的时候也必须一次性向上交付100字节的数据不能对100字节的数据多次交付发送端发送多少次数据发送的数据大小是多大那么接收端就向上交付多少次交付对应数据的大小。即不可拆分不可合并。 UDP的缓冲区  在之前学习Linux时我们就已经提到过了缓冲区的概念其实在UDP协议中也是有着缓冲区的概念的。 如上图当应用层程序调用系统调用进行通信时如果进行读取 UDP先将下层获取的报文读取到接收缓冲区然后上层通过调用系统接口将接收缓冲区中的报文进行读取。但是要注意接收缓冲区不能保证收到的UDP报文的顺序和发送的UDP报文的顺序是一致的同时当接收缓冲区中的数据满了时后续再到达的UDP报文会被丢弃。 上面讲的是UDP的接收缓冲区UDP没有真正意义上的发送缓冲区当上层发送数据时会直接将数据发送到操作系统内核然后由内核通过网络层以及下面几层进行数据的传送。 全双工和半双工 举一个简单的例子就是你说话的时候我不能说话你说完了我才能说这叫做半双工你说话的时候我也可以说这叫做全双工。 在计算机网络中半双工就是当前端口往对端发送报文时对端不能发送只有当当前报文发送完毕对端才能进行报文的发送。全双工就是当前端往对端发送报文时同时对端也可以同时往当前端发送报文。 TCP协议 TCP协议是传输层中又一个比较重要的协议TCP协议的报文图示如下。 TCP的特点  确认应答。这是TCP保证可靠传输的核心机制。  面向连接。TCP报文的发送必须建立连接。  全双工通信。接收对方的报文时同时可以向对方发送报文。  超时重传保证可靠性。  流量控制双端之间。  拥塞控制与网络实时状态关联。  面向字节流。  有序传输按序接收保证可靠性。 TCP的所有特点概括起来就一个特点------可靠。  何为应答机制? 大家可以想象生活中的一个场景老师在上网课老师提出了一个问题那么此时老师怎么样保证自己提出的问题已经被同学们听到了呢实际上老师是在看到同学们做出响应之后才能知道自己的问题被同学们听到了。 在计算机网络中也是一样的当前端口发送TCP报文给对端也是通过接收到对端做出的响应之后才知道自己的报文被对端接收到。 TCP报头分析  源端口目标端口数据偏移(报文首部长度) 依旧是两个问题。 TCP报文如何实现封装和解包TCP报文如何实现分用   先来回答第一个问题在TCP报文中可以看到有着一个4位数据偏移的字段通俗点来说4位数据偏移其实就是4位报文首部长度4个bit位表示的10进制数的范围为0~15TCP报文长度的基本单位与UDP不同UDP报文长度的基本单位是1字节但是TCP报文长度的基本单位是4字节(考虑到了对齐)所以对于TCP报文而言 因为TCP报文首部长度最大为15也就意味着报文首部的最大长度为60字节。我们可以根据这4个bit位算出报文首部的长度然后加上数据的长度就实现了报文的封装。分用就更为简单因为我们已经知道了报文的总大小和首部大小所以根据报文的总大小减去报文首部大小就得到了数据即有效载荷的大小就可以轻松实现解包。 第二个问题与UDP的第二个问题的答案类似可以通过16位目标端口号实现分用。  序号  那么有一个问题client端口可能依次发送多个报文我们规定报文发送的顺序是什么样那么sever端接收报文的顺序就是什么样因为如果发送的顺序和接收的顺序不同可能会导致信息发送的错误那么我们是如何保证TCP报文的发送顺序和接收顺序是一样的呢 这是因为在TCP的报文中有序号字段这个序号可以表示报文发送的顺序至于按顺序发送的报文是否是按顺序送达的我们不关心我们最终会根据发送的报文中的序号来依次进行接收。 确认号  我们知道当前端口发送完报文之后是通过接收对端的响应来得知自己发送的报文已经被对面接收到了。那么当当前端口发送了多个请求报文并且得到了多个响应报文那么当前端口是如何知道这些响应报文对应的是哪些请求的报文呢 其实在TCP报文中还有一个确认号确认号一般比序号大1当当前端口得到响应报文之后会分析报文中的确认号来得知是哪一个请求报文的响应。且可以通过确认号得知当前确认号之前的所有请求报文都已经被接收到。 还有一个问题为什么TCP报文中既有32位序号又有32位确认号 发送请求的时候将32位表示为序号发送响应的时候将32位表示为确认号不就行了 其实大家可以仔细想想响应报文又何尝不是一个请求报文呢当前的响应报文可以通过确认号去告知对端上一条请求报文被接收也会有自己的序号去发送给对端最终通过对端的响应报文得知当前响应报文是否被接收到。          窗口 UDP协议具有接收缓冲区但是没有真正的发送缓冲区。但是在TCP协议中TCP协议既具有接收缓冲区也具有发送缓冲区。我们通过图示为大家进一步讲解。 如上图当client调用write/sendto接口时相当于先将应用层的数据拷贝到了client的发送缓冲区然后TCP协议会将发送缓冲区中的数据发送到sever的接收缓冲区最终sever的应用层程序会调用系统调用接口read/recvfrom将接收缓冲区中的数据读取到应用层。  会什么会有缓冲区的概念我们直接给出答案。 提高应用层传输数据的效率将应用层和TCP协议进行解耦。因为有了缓冲区的概念之后应用层只用考虑如何把应用层数据发送到缓冲区中就可以至于之后数据在TCP的传输细节应用层根本不去考虑因为剩下的事情都是由TCP协议内部做的。TCP是传输控制协议所以数据发送多少如何发送这些都是TCP去考虑的事情也只有TCP协议能够做到这些所以也必须有缓冲区的概念。  可是大家来想一个问题既然TCP中有缓冲区的概念那么这个缓冲区肯定会有大小限制的如果发送至接收缓冲区的数据因为应用层没有及时读取缓冲区的数据或者说应用层读取缓冲区数据的速率比较慢那么此时缓冲区会很快的被数据填满。那么如果缓冲区即将被填满或者已经被填满此时如果TCP发送端仍然发送了大量的数据报文因为接收缓冲区的大小不够就有可能报文被丢弃也就是会有丢包现象虽然TCP协议中会针对丢包现象有重传机制但是这并不能从根源上解决丢包的现象。那么如何从根源上解决丢包这一现象呢 为了解决丢包这一类问题在TCP协议的报文的报头中有了16位窗口的概念当发送端发送报文时接收端会做出响应同时在响应报文中会填充16位窗口字段代表着自身的接收缓冲区还剩余多大的内存所以当发送端接收到接收端的响应报文时会根据响应报文报头中的16位窗口的大小及时的去调整自己报文的发送数量和大小。 6个标志位  TCP报头为什么会有标志位的概念这是因为在日常生活的情景中一个sever端可能会收到多个client端的请求报文所以为了区分大量报文TCP协议中有了6个标志位来区分报文的种类。 6个标志位分别为URG,ACK,PSH,RST,SYN,FIN接下来我们依次为大家讲解这六个标志位的作用。 ACK 我们知道TCP有确认应答机制所以当发送端发送了一个请求报文那么当接收端接收到请求报文就会发送相应报文作为对请求报文的确认应答当接收端接收响应报文时就知道自己发送的发送报文已经被接收端接收到。所以只要当前报文是一个响应报文就会将响应报文的报文头部的ACK标志位置为1代表着当前报文是一个响应报文。 SYN  TCP协议是一个面向连接的协议所以基于TCP协议的通信必须先建立连接。那么TCP协议是如何建立连接的呢 这就牵扯到了TCP通信中一个很重要的知识点------三次握手。通过图示为大家简单先讲解一下三次握手。 所以如果报文是一个建立连接的报文就要将报文的报头中的SVN标志位置为1。  RST  仍然是三次握手我们发现三次握手的前两次握手是不容易丢包的因为前两次握手的请求都会有响应 所以只要前两次请求没有收到响应我们就认为该请求被丢包了但是第三次握手因为没有响应所以第三次握手很容易被丢包,一旦第三次丢包就意味着第二次请求没有得到响应会导致一系列严重的问题图示如下。 如果当前请求报文是为了重置连接那么就要将该报文报头中的RST位置为1。 PSH 我们在上文已经讲过了TCP协议中有发送缓冲区和接收缓冲区。如果TCP协议的接收缓冲区已经快被填满那么此时发送端发送数据的大小和数量就会降低所以此时发送端就会发送一个报文并且将该报文的PSH字段置为1即告知接收端快速的将接收缓冲区中向应用层进行交付。 URG 我们知道TCP通信过程中发送端报文的发送是具有顺序的接收端接收报文的顺序也必须按照报文发送的顺序进行接收也就意味着发送端发送报文的顺序是什么样接收端接收报文的顺序就是什么样进一步也就意味着被上层读取的顺序也是基本确定的。但是如果此时我们就像让某个报文插队顺序接收之后但是被率先被上层读取呢 那么此时就需要将该报文的URG位置为1表示当前报文发送的是紧急数据要将当前报文的数据率先为上层交付。 所以如果当前报文要发送紧急数据想让当前报文被接收之后率先向上进行交付就需要将报文的报头的URG位置为1。  FIN TCP是面向连接的通信协议所以要建立连接最终肯定也是会断开连接的所以如果当前请求报文的目的是为了断开连接就要将当前报文的报头中的FIN标志位置为1。 断开连接又会引入另一个比较重要的知识点就是四次挥手断开连接简单图示如下。 如果当前报文是一个请求断开连接的报文就要将当前报文的报头的FIN位置为1。  TCP的三种机制 确认应答机制 确认应答机制上文已经讲述过我们在此作为补充。 TCP有序号我们能理解这是为了方便将来接收报文时对报文进行有序接受但是这个序号是怎么来的呢 其实我们可以认为TCP的发送缓冲区就是一个字符数组数组的每个元素占用了一个字节如果一个报文在缓冲区中占用了缓冲区的空间我们就把该报文在缓冲区中占用的最后一个字节的空间的下标作为当前报文的序号如图我们当前的报文的序号就应该是100因为占用的最后一个字节的空间的下标就是100。  超时重传机制  当我们在TCP协议的发送端发送了一个报文那么此时就会等待对端的响应因为有了响应就意味着当前报文已经成功的被对端接收到了。 那么有没有一种可能当发送端发送完报文之后为了确认对端收到了报文会一直等待对端的响应。如果此时接收端将网线拔掉了此时发送端是不知道对方将网线拔掉的所以此时通俗的来说发送端是一直在干等的难道就这样一直干等下去吗 肯定不是这样子的我们规定在发送端发送了报文之后发送端会进行等待等待对方的响应但是这个等待时间是有一个限度的我们会规定一个最大的等待时间等待的时间会根据操作系统的不同以及网络环境的不同网络带宽大就设置时间短带宽小就反之动态进行设置确保在这个时间内一定会收到对端的响应如果此时超过了这个时间还没有收到对端的响应我们就认为当前报文丢包了对端没有接收到发送的报文所以会进行报文的重传即再次发送。 问大家一个问题发送端在规定的时间内如果没有接收到对端的响应一定是对端没有接收到报文吗并不是通过图示为大家解释。 所以针对上述情景当client端在规定时间内没有接收到对端的响应就认为发送的报文对方没有接收到就认为丢包了所以会进行超时重传。 但是针对上图中的第一个情况如果sever端没有接收到报文重传最终让sever端接收到报文这没有问题但是如果是第二种情况呢sever端接收到了报文只是返回响应及响应到达的时间比规定时间大我们仍然认为sever端没有接收到进行了重传那么sever这不就是接收到了重复的报文吗 是的道理是这样子的但是与此同时sever端的TCP协议内部会有去重机制因为重传的报文的序号是一致的所以可以根据序号进行去重。  如果真的对端把网线拔了那么此时发送端一直发送一直重传这样不就会导致发送端浪费资源一直在做无用工吗 针对这种情况TCP协议内部又规定了重传的次数如果重传的次数到达了这个规定的重传次数那么发送端就不会再进行重传了。  连接管理机制 TCP协议是一个面向连接的协议所以使用TCP通信时必须经过建立连接数据传输断开连接这三个步骤。所以对于连接的管理对于TCP而言是非常重要的所以TCP对于连接的管理有着自己独特的管理机制。 先对连接的整个过程进行图示。 我们再次对三次握手和四次挥手进行进一步探究。两个问题  为什么要三次握手建立连接1次2次4次为什么不可以呢为什么要四次挥手断开连接 先来回答第一个问题我们使用3次握手有3个原因。 保证双方的主机都是正常的。因为TCP是全双工通信也就是双方可以同时接收对方的数据也可以同时向对方发送数据而三次握手是能够保证双方都具有收发能力的最小次数通过三次握手能够保证保证TCP的全双工通信。TCP三次握手建立连接是比较安全的。 我们先来对前两个原因做出解释我们先简单分析一下当client端向sever发送建立连接的请求时一旦sever接收到了建立连接的请求此时sever就知道了client的发送能力和自己的接收能力是正常的然后sever向client发送了同意建立连接的响应并且发送了立即建立连接的请求一旦client接收到了响应和请求client就认为自己的发送能力是正常的因为收到了响应sever的接收能力是正常的因为收到了响应sever的发送能力是正常的因为收到了响应和请求自己的接收是正常的因为接收到了响应和请求client端就建立了连接然后client向sever发送我已经建立了连接响应当sever接收到了client端的已经建立了连接的响应之后就认为自己的发送能力是正常的client的接收能力是正常的至此双方都知道自己和对方的接收和发送能力都是正常的所以就保证了TCP的全双工以及双方机器都是正常的。 第三个原因这是因为如果是只有1次握手或者2次握手此时的服务器就很容易收到恶意的SYN洪水攻击使得服务器资源被恶意占用导致服务器响应卡顿。 图示如下。 上述图示对于1次握手建立连接不可行的解释但是同样对于2次握手建立连接也是可行的因为二次握手就多了一次sever的响应但是对于恶意机器而言我不管你回不回应我只是发送请求就行所以对于恶意机器而言不会产生资源的消耗但是对于sever而言就不一样了因为创建了大量的数据结构产生了大量的资源消耗所以1次2次握手就不行那么三次握手没有安全问题吗当然是有的但是因为三次握手必须保证有对端的响应一旦对端有了响应对于对端而言同样是要消耗大量的资源的对于安全机器而言成本会高很多所以三次握手的对于普通恶意攻击的防护是比较高的。 再次回答第二个问题为什么需要四次握手断开连接呢 这是因为四次握手是一个协商的过程可以理解为双方签订了一个协议甲方同意乙方的规定乙方同意甲方的规定双方都同意之后协议达成这对于断开连接也是一样的双方都需要进行断开连接的请求的发送等待对方进行应答最终双方都断开连接。  两种等待状态  TIME_WAIT 在上图的断开连接的图示中有了TIME_WAIT状态TIME_WAIT状态是谁先发送了断开连接的请求谁就会进入这个状态一般情况下是client端率先请求断开连接所以一般情况下是client端具有TIME_WAIT状态。 我们在sever端进行测试让sever端主动断开连接。sever源代码如下。 int main(int args, char *argv[]) {if (args ! 2){return 1;}// 作为服务器端// 1.创建socket文件int Listen_fd Socket::Sock();// 2.绑定IP和端口号Socket::Bind(Listen_fd, atoi(argv[1]));// 3.进行监听Socket::Listen(Listen_fd);// 4.持续的获取链接for (;;){sleep(1);int newfd Socket::Accept(Listen_fd);}return 0; }运行可执行程序我们发现此时的sever端的是LISTEN状态。 我们在本地使用telnet 进行连接。 然后我们ctrlc,主动关闭sever端再次观查sever的状态。 我们发现此时sever端变成了TIME_WAIT状态。 当sever主动断开连接之后sever端再次启动绑定端口时就会出现bind err的错误。 首先我们分析一个问题当sever处于TIME_WAIT的状态时连接是否已经断开了其实上图已经很明显了当client端此时我们认为为sever因为sever是主动断开的一方处于TIME_WAIT的状态时连接其实是还没有断开的只有在TIME_WAIT状态下等待2MSL时间之后进入CLOSED状态时此时我们才认为断开了连接。所以答案就已经很明显了因为当我们主动结束掉sever进程时sever进程的网络状态是TIME_WAIT状态并不会立即断开连接所以sever的进程实质上是还没有结束的所以此时如果再次进行端口的绑定就会导致多个进程绑定同一端口号我们知道一个端口号只能绑定一个进程所以此时就会出现绑定错误。那么如何处理这种绑定错误呢 可以使用setsockopt接口解决bind绑定错误的问题。 static int Sock(){int fd socket(AF_INET, SOCK_STREAM, 0);if (fd 0){cout socket create error errno endl;exit(1);}int opt 1;setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,opt,sizeof(opt));return fd;} 此时就可以重复的绑定端口。  上文我们也提到了MSL的概念那么MSL是什么为什么要在TIME_WAIT状态下等待2MSL才能进入CLOSED状态呢 先回答第一个问题MSL我们称之为报文传输的最大时间即一个报文传送到对端的最大时间。 再来回答第二个问题在TCP传输报文的过程中我们也说过报文的接收顺序必须与报文的发送顺序一致但是这是建立在有应答的基础上的四次挥手的最后一次ACK是不需要应答的所以最后一次的ACK可以被提前接收所以当最后一个ACK被发送之后等待了一个MSL就将状态改为CLOSED就会导致连接关闭进而导致历史的报文有一部分没有收到所以设置为2MSL的第一个原因就是为了使得历史数据被收到。第二个原因就是在四次挥手中由sever端在LAST_ACK状态发送断开连接的请求时此时开始计时如果该报文被cient收到也就是一个MSL此时client端接收后立即应答在一个MSL之后到达sever端所以整个过程需要2MSL,如果sever端在一个MSL时间没有收到client的应答就会认为自己发送的请求断开连接的请求没有被client端收到所以就会进行请求的重传此时重传到达client端又是一个MSL,所以从client端发送响应到接收sever重传刚好就是2MSL但是此时在接收到sever重传的请求报文时client端是没有断开连接的所以是可以接收的。这就是为什么client在处于TIME_WAIT状态时要等待2MSL的时间才会进入CLOSED状态的原因。 综上client从TIME_WAIT状态到CLOSED状态有两个原因。 保证client端历史报文可以被sever端接收。保证client端可以接收到sever端的重传请求。 CLOSED_WAIT  在四次挥手中只有当sever处于CLOSED_WAIT状态调用了close关闭连接的接口此时sever的状态才会变为LAST_ACK状态。那么如果在sever端不显示调用close就意味着sever的状态永远是CLOSED_WAIT状态的。 依然是上述sever代码获取了连接但是不调用close接口关闭连接。 那么服务器长期处于CLOSED_WAIT状态有什么影响吗 肯定是有影响的sever长期处于CLOSED_WAIT状态意味着sever一直没有关闭连接所以sever就会一直维护这个没有断开的链接如果client接受了大量的连接而不去关闭连接sever就要去维护大量的连接sever维护是用数据结构维护的大量的链接就意味着大量的数据结构就意味着要浪费大量的资源有小伙伴可能会去说手动关闭连接不就行了确实是可以这样的当有大量的client访问关闭连接是一件代价很大的事情。虽然主动关闭连接的是客户端但是依然会有其它的客户端去访问如果此时sever手动关闭造成的损失是极大的双11关闭服务器一秒试试。所以我们一定要记得手动的写上close这个关闭连接的函数。 滑动窗口 TCP协议中也有着滑动窗口的概念那么什么是滑动窗口呢 滑动窗口就是上图中tcp发送缓冲区的一个区域这个区域的前半部分是已经发送且已经收到确认的报文数据滑动窗口中的数据就是即将要发送或者已经发送但是未收到确认的报文第3个区域就是未发送的报文。 为什么会有滑动窗口的概念我们直接给出结论是为了提高效率。 本来是一请求一响应但是这种方式效率太慢采用了多请求多响应的模式直接发送多个报文多个报文的总大小就是滑动窗口的总大小上图滑动窗口的大小是4000字节。 需要注意的是前四次请求不需要响应之后每次的多次请求都必须根据上一次最后一个响应报文的16位窗口大小调整这次传递报文的大小。  为什么称为滑动窗口这是因为1000号报文被发送且收到1000号报文的确认的时候滑动窗口会向右移动准备发送5000号报文。图示如下。 需要注意的是滑动窗口的大小是动态变化的接收到最后一个请求报文的响应之后就要根据最后一个报文的窗口得出接收端缓冲区的剩余大小调整滑动窗口的大小。  滑动窗口的丢包处理 我们使用滑动窗口的策略在进行报文的传输过程中必然会面对丢包现象。 中间报文的响应丢失 中间报文的ACK丢失但是收到了之后的报文的确认。 针对上图这种情况如果2000号和3000号报文的响应丢包了此时我们没有收到响应但是我们收到了4000号报文的响应针对这种情况我们怎样处理呢 其实这种情况不用担心因为报文是按序进行接收的所以如果接收到了4000号报文那么就意味着4000号报文之前的报文应该是全部被接收到了的。所以一旦我们收到了4000号报文的响应就能根据确认号4001得知4000号报文已经被接收那么4000号报文之前的所有报文都是已经被接收了的所以不用担心中间的报文的响应丢失。  中间报文的请求丢失  第一种情况是响应的丢失但是这一问题被TCP确认应答中的确认号这一机制给成功解决但是如果是中间的某一请求报文丢失呢如下图中的2000号报文被丢失。 这种情况是存在的那么当2000号报文丢失之后之后的报文仍然会被按序进行接收也会做出响应但是此时的响应报文中报头的确认号不能是发送的报文的序号对应的确认号 因为确认号的本质其实就是代表着当前确认号之前的所有序号的报文都已经全部被接收到了。所以当前发送失败的请求报文之后的所有请求报文的确认号都必须是当前请求报文之前的报文的确认号因为只有这样才能正确的保证确认号本身的含义就是确认号之前的报文已经全部被接收到了。 所以当接收端连续接收到了三个相同的确认号之后此时就会知道是1000号报文之后的请求报文没有被送达所以此时就会进行重传当2000号报文被重发且被对端接收到之后此时返回的确认号就应该是5001因为此时5001号之前的所有报文都已经被接收到了。 上述这种发送端接收到三个同样确认号的响应报文之后进行重传的这种重传机制就叫做快重传。 流量控制 什么是流量控制 发送端根据对端报文报头中的16位窗口字段得知接收端接收缓冲区的接收能力从而调整自身发送缓冲区中的滑动窗口的大小保证报文高效传输的机制这一机制就叫做流量控制。  那么当我们在第一次使用流量窗口发送数据时我们知道此时发送的报文是不需要响应的那么问题来了发送端是如何知道对端的接收能力从而一次性自信的发送大量的报文的呢 其实回过头来大家可以想想TCP通信的全过程建立连接数据交换断开连接无非就是这三步滑动窗口发送报文就是在第二步所以在滑动窗口发送数据之前还要进行三次握手建立连接在三次握手前两次建立连接的过程中其实双端就已经获知了对方的接受能力,为什么是双端这是因为TCP是一个全双工通信接受对端数据的同时也可能在发送数据。所以滑动窗口第一次发送大量的报文是因为在三次握手期间已经知道了对端的接收能力窗口大小。         当接收端的窗口大小为0时后续如果发送端要发送数据此时就有两种方法可以获知接收端窗口的大小一是通过发送端发送窗口探测的请求然后由接收端发送响应告知发送端接收端的接收缓冲区的大小一种是直接由接收端发送一个相应报文告知发送端自己的窗口大小。 同时TCP首部还有一个40字节的选项中间还包含了一个窗口扩大因子M实际窗口字段的大小是16位窗口字段左移M位。 拥塞控制 在讲拥塞控制之前我们都是站在发送端和接收端的角度上去考虑的 如果引入了网络呢 引入了网络之后发送端的滑动窗口的大小此时还能只以接收端的窗口的大小为依据吗试想一下如果此时滑动窗口的大小符合了对端的接收能力但是此时如果此时滑动窗口就发送了大量的报文但是此时网络状态是十分拥堵的就会导致大量的报文被发送之后频繁地进行丢包重传这样就会造成大量的没有必要的资源的消耗所以发送端的滑动窗口发送报文时必须考虑网络状况。 那么TCP是如果根据网络状况来及时调整滑动窗口的大小来发送数据呢  TCP中提出了拥塞控制的概念。如何实现拥塞控制呢 在TCP中引入了慢启动的机制同时也提出了拥塞窗口的概念。 先来讲解拥塞窗口拥塞窗口区别于滑动窗口和16位窗口拥塞窗口是出于网络中的有一个对滑动窗口大小约束的一个窗口可以通过这个窗口实时检测网络的传输能力。对于拥塞窗口而言的一开始我们让滑动窗口的大小为1然后发送的报文一旦接收到了响应就让拥塞窗口的大小为前一次拥塞窗口大小的2倍之后呈指数增长我们所说的慢启动其实就是刚开始时拥塞窗口的大小都是比较小的。 如图所示一开始拥塞窗口的大小都是1然后获取到响应之后拥塞窗口的大小呈指数增长难道拥塞窗口的大小一直呈指数增长吗  当然不是我们规定滑动窗口的大小为拥塞窗口和16位窗口的最小值所以当拥塞窗口的大小大于16位窗口的大小时其实也就没有什么意义了。所以我们规定了一个阈值这个阈值就为TCP刚开始通信时慢启动的阈值(ssthresh)当拥塞窗口大小到达这个阈值时此时拥塞窗口的大小不再指数增长而是呈线性增长在拥塞窗口呈线性增长增长到了一定的大小时此时一旦发送端进行了超时重传那么此时拥塞窗口的大小就会瞬间变为后又1然开始慢启动此时慢启动的阈值为重传前拥塞窗口大小的一半后续依然是按照前面的逻辑进行TCP通信。 单独的流量控制和拥塞控制是不能提高保证TCP通信的效率的只有流量控制和拥塞控制结合起来将网络的实时传输能力和接收端的接收能力都考虑进去才能真正意义上提高TCP通信的效率。 延时应答 我们上文多次讲述了一个概念叫做接收缓冲区。当发送端发送数据接收端接收数据到接收缓冲区缓冲区的数据可以被上层取走。当发送端发送了报文之后接收端接收报文到缓冲区中此时如果接收端立即给发送端发送了响应那么此时响应报文中的窗口的大小一定是原有的接收缓冲区的大小减去接收的报文的大小长此以往随着接收缓冲区中接收的报文越来越多此时如果都立即做出了响应那么接收缓冲区的接收能力就越来越弱导致后续发送端发送的报文的效率变慢。         所以此时我们就引入了延时应答的机制让接收端接收到报文到接收缓冲区中之后不立即做出响应而是等待一段时间等待应用层取走数据之后再做出响应此时响应报文中的窗口大小每次都是处于一个很大的值接收端的接收能力也是比较大的所以发送端的滑动窗口的大小总是会保持一个较大的值这样就能保证在网络的传输能力较好的前提下提高报文传输的效率。 捎带应答  捎带应答其实也很好理解建立连接的三次握手中的第二次握手就是捎带应答第一次握手发送端向接收端发送了请求连接的报文第二次握手接收端发送了同一连接的响应报文以及请求获取连接的请求报文注意这个相应报文和请求报文都是同一个报文也就意味着在第二次挥手时接收端发送获取连接的请求时顺带做出了同意连接的请求这就是捎带应答。 面向字节流和粘包 我们知道UDP是面向数据报的TCP与UDP不同TCP是面向字节流的面向字节流又是什么意思呢 面向字节流即无论应用层一次向发送端发送了多少的数据包如http请求当发送端将这些请求发送至接收端时会将这些请求拼接成一个字节序这个字节序是没有边界的接收端会将这些字节序随意的向上交付可能交付一次完成也可能交付多次完成所以就会涉及字节序的拼接和分割。这样就会导致http请求可能会被拆分最终合并成多个非法的http请求这就是粘包现象。 TCP如果解决粘包现象呢 总结一句话就是明确包和包的边界TCP实际上是解决不了粘包的问题的只有应用层自己可以解决粘包的问题 如http协议中的空行报头中的content_length属性以及http协议的每行中的\n上层在进行接收端数据的读取时应该以这些特殊符号和字段作为读取的依据确保读到完整的http请求其它的数据包也是类似的要在应用层去设计读取的规则保证读取时每个数据包的完整性。 那么UDP会有粘包现象吗 答案是不会有的因为UDP是面向数据报的协议所以当应用层向发送端一次发送大量的数据包如http请求时发送端讲这些数据包向上进行交付时也必须一次性向上交付发送过来的同样大小的数据包整个过程不会涉及对应用层发送的数据包进行拆分与合并所以就不会导致粘包的现象。 TCP异常 TCP的异常总共有三种情况。 进程关闭。我们知道进程关闭时会同步的关闭进程所打开的文件描述符所以和正常关闭连接时调用close接口没有什么区别。机器重启。机器重启其实和进程关闭没有什么两样因为机器重启也伴随着进程的关闭。机器断电/网络断开。这种情况下因为网络已经断开此时客户端不能向服务器端发送断开连接的请求所以发送的报文无法被送达至客户端此时自身也不具有重传的能力当服务器端发送数据时发送的数据如果在超时重传的时间时内没有收到响应就会进行数据的重传但是因为网络一直是断开的所以当重传的次数到达了一定的次数时就会向客户端发送reset请求最终服务器端关闭连接。 TCP与UDP对比 TCP最大的优点就是可靠因为其是面向字节流的协议一个符号都可以被TCP明显的甄别出来可以用于文件传输等需要可靠传输的情景。UDPUDP区别于TCPUDP的报头是8个字节TCP的报头最大是60个字节而且UDP的报文也是有大小限制的但是TCP的报文没有大小限制,与此同时因为TCP要保证可靠传输会有确认应答超时重传流量控制和拥塞控制等多个机制所以这就导致了UDP传输的速率是高于TCP的,UDP可以用于对于实时性要求比较高的场景比如直播打视频电话。 listen的第二个参数  在之socket编程中sever端使用listen接口进行监听时我们默认设置了第二个参数为5那么第二个参数到底有什么含义吗  其实第二个参数1就是全连接队列中全连接的个数在TCP中我们引入了全连接和半连接的概念全连接就是当sever端得知client建立了连接之后进入ESTABLISHED状态之后此时client和sever都认为client连接已经建立好了连接那么此时的连接就是全连接当sever处于SYN_RCVD和ESTABLISHED之间的状态我们就称之为半连接。 对于sever而言一次性可获取的连接是有限的因为sever的资源也是有限的。全连接就意味着client和sever端连接已经建立完成所以只需要等待后续进行获取连接就可以进行后续的数据交互但是因为sever的资源是有限的一次性获取不了大量的连接如果此时sever的资源已经被使用完了当大量的全连接到来时如果不及时的获取这些全连接就会导致这些全连接依次的断开在某些场景下会造成大量的损失所以就引入了一个全连接队列的概念将未被accept的全连接放在一个全连接队列中当使用完sever资源的全连接都一一断开连接之后全连接队列中的队头的全连接会被立即获取这样就能充分的使用sever的资源而不会导致sever资源空闲而未被使用的情况但是全连接队列也不宜过长这样就会导致在队列尾的连接等待过长时间造成饥饿问题。 以上便是TCP的所有知识点至此传输层的主要协议我们已经讲解完成。 本期内容到此结束^_^
http://www.w-s-a.com/news/833978/

相关文章:

  • 有关网站建设的标题仿亿欧网wordpress
  • 网站建设公司销售招聘常用的搜索引擎有哪些?
  • wordpress中.htaccess新上线的网站怎么做优化
  • 家教网站怎么做网站建设品牌推荐
  • 青岛做外贸网站建设茶叶公司网站建设策划书
  • 个人电脑做网站主机三合一网站
  • 用html框架做网站怎么在.Net中做团购网站
  • 怎样建一个自己公司的网站制作网站需要钱吗
  • 联盟网站制作wap网站制作公司
  • 美丽乡村建设发展论坛网站wordpress 仿站 教程网
  • 浙江省建设注册管理中心网站首页优设设计网站导航
  • 台州小型网站建设国内免费的建网站平台
  • 自己做网站不推广网站建设工作室发展
  • 有女人和马做网站吗宁波seo优势
  • 网站做用户记录表电商运营推广计划方案
  • 网站备案认领杭州网页设计公司招聘
  • 易签到网站开发设计做网站运营有前途吗
  • 南通网站建设心得2023必考十大时政热点
  • 苍溪建设局网站公建设计网站
  • 九歌人工智能诗歌写作网站电子商务网站建设项目书
  • 做外贸的经常浏览的三个网站律师做哪个网站好
  • 中国公路建设招标网站长沙大型网站建设公司
  • 沈阳企业网站模板建站注册电子邮箱免费注册
  • 如何做简洁网站设计企业网站排名优化方案
  • 东莞网站建设服务商做触屏网站
  • 外国网站代理音乐网站建设
  • 珠江网站建设广安广告公司
  • 高端创意网站建设网页制作咨询公司
  • 网站建设及发布的流程图wordpress文章摘要显示
  • 淮北网站网站建设省好多会员app