| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> 计算机网络-自顶向下方法 读书笔记 -> 正文阅读 |
|
[网络协议]计算机网络-自顶向下方法 读书笔记 |
运输层 一 为何有些应用依然适用udp而不是可靠的tcp *1 udp没有拥塞控制,而tcp的可靠传输/拥塞控制会不停重试/等待 确认数据发送成功,对于一些延迟容忍度低的应用比如电话会议音视频会议不可接受,另外如果需要处于重压状态下依然能够正常运行,这时候会选择udp而不是受拥塞控制的tcp【难以实现】 2 udp不用握手建立链接 ,而tcp需要三次握手在大多数场景下加剧了延迟。如dns运行在udp上就是因为udp没有握手引入的延迟。而web/http建立在tcp上因为他需要非常可靠至关重要。 3 udp链接不需要维护状态,而每条tcp链接需要维护包括发送缓存/接受缓存/拥塞控制参数/序号确认号的参数,udp不需要这些,他能支持更多的活跃客户 4 udp开销小,udp报文之需要8个首部字节,而tcp报文需要20个 二 当分组丢包率低时 并且为了安全原因,某些机构阻塞udp流量 这句话怎么理机? 这里我猜测一个原因,由于udp没有拥塞机制,他可能会把某个带宽挤占满从而导致一些正常的tcp流量得不到服务/服务质量下降,为了安全/质量考虑,就把udp流量给禁掉了。 三 udp udp机制显得很简单,从应用成收到数据后,即加上目的端口和源端口,标记长度与校验和(用于错误检测)后,直接发送给ip层了,所以他没有任何可靠性与拥塞控制性。 这样的特征也使得udp像是网络上的流氓协议[没有任何自我约束,抢占带宽】, 另外报文也不进行分割,应用层一次传多少数据下来就当作一个报文。 此外,由于udp传输之前不需要建立连接,他可以用于多播,而面向连接的点到点的tcp是不能的。 四 可靠传输原理 这部分是为了介绍tcp的可靠传输铺垫的,tcp总的来说有三大特征 可靠传输(差错恢复),流量控制(注意这里值得是端到端的流量控制),拥塞控制(对网络状态负责的流量控制),【尽管后面两个的控制的实现方式一致,但解决的问题不一样需要注意。】 可靠传输需要借用的技术 注意:这里指考虑单工,即A向B发送数据,其实双工也是类似,只不过为了简化描述。 1 通过接收端的确认机制 发送端发送一个数据报文,接收端收到后回复ack,尔后发送端再次发送。这种叫做停等协议。 考虑一种情况,如果回复的ack丢失了or出错了怎么办? 解决办法是引入序号机制+超时重传机制,即ack需要带上对确认报文的序号(当然发送的报文刚开始必须要有序号),如果发现没有收到改ack,则发送端超时了再发送上次的报文。 那么问题来了,超时的时间如何确定?发送方多久没有收到期望的ack表示即超时了? 这里至少需要等待一个rtt时间,当然更精确的时间tcp在实践中后面会讲述到。 2 考虑效率 这种停等协议的效率其实是很低的,网络带宽很大,你停停等等的发送数据,会让带宽大部分时间都处于闲置状态,这里就引入了流水线,即不等上一个报文的ack收到,发送方继续发送报文,比如继续发送3个报文 如果采用了流水线机制,会引入问题,如果真的有丢包产生,即期望ack迟迟未到而超时,此时发送端应该如何?这里有两种办法:回退N和选择重传。 这里引入一个值N:允许发送方发送多个分组而不需要等待确认。这个N也叫做滑动窗口大小 其中从32到51即为滑动窗口,其中32-45是已经发送出去的但还没被ack的,46-51是发送端可以继续发送的。 如果收到的ack还是对32的ack 如果选择回退N,那么就要把从32到45的数据再发送一次。反之如果收到了ack 33,则滑动窗口可以向右移动一个。 当然这种回退N的做法比较粗糙,可能32没到,但33-40这些都能够收到了,所以就有了选择重传,不过这需要接收端的配合:是否采用累计ack机制,如果采用累计ack[即每次ack已经收到的最小连续有序的报文的末尾的那个ack,而不ack无序的报文] 这里涉及到的几个技术,包括定时器、序号、确认号、ack等技术都会在tcp中用来实现可靠传输。 三 tcp 上面讲了tcp主要有三个方面,首先来看可靠传输是如何运用上面讲述的原理实践的。 在之前线介绍下tcp连接与报文结构 1 tcp是端到端的连接,是一条逻辑连接,一条连接的状态仅保留在【两个通信端】的tcp程序中,而中间的设施(包括路由器交换机等)都没有。 2 tcp是全双工 3 关于mss与mtu:tcp在组装tcp报文时,他从应用层收到数据后会按照一定大小进行切割,这个大小就是mss,而mss取决于mtu,mtu表示最大链路层帧的长度,一般以太网和ppp链路为1500字节,所以典型的mss一般为1500-20-20=1460,其中20+20为tcp的头部与ip头部长度。 所以一个文件通过tcp传输时会被切割为一个个mss长度的数据然后被组装起来。 4 tcp报文结构:源端口号/目的端口号,序号/确认号,首部长度/标记字段,接受窗口,校验和/紧急数据指针。一般情况为20字节。 5 最重要的两个字段时序号/确认号:这里tcp是流式的协议,这里序号/确认号也都是字节的编号,序号标记了本报文在整个报文段(文件被划分为多个报文段)中的首字节的编号。确认号是期望对方下次发送报文的序号。 可靠传输 6 重传时间的管理:timeoutinternla=estimaterRTT + 4 * DevRTT,这里estimateRTT表示评估下来的rtt时间,他时刻处于动态变化中,estimateRTT=EstmateRTT * a + (1-a) * samepleRTT,其中simpleRTT是上次实际的RTT,在实际中a一般取值1/8,可见把实际RTT的赋值权重更高,而DevRTT则表示RTT的方差,因为要考虑RTT的起伏变化。总的来说时间就是对RTT的一个预估值。 7关于快重传与delay ack: 如果服务端收到了三次冗余的ack,则服务端会立即重传该报文而不必等待超时。delay ack:如果一切都正常,那么客户端不会立即发送ack,而会等待一段时间后看是否还有连续正常的数据到来,这时候发送对后面数据的ack,这样效率更高(因为是累积ack),具体时间约为(500ms) 8 tcp到底是一个回退N还是选择重传的实现:其实是两者的一个折衷结合。 流量控制 第二个点是tcp的流量控制,这里注意不是拥塞控制, 1 流量控制是指发送方要考虑到接收方的接受能力,不能发的太快导致接收方应用程序接受不及时而溢满了对方的接受缓冲区。 2 本质上流量控制和拥塞控制都是通过对发送方发送速率的限制来达到目的。 3 流量控制的核心是:每个tcp连接让发送方维护一个接受窗口,接受窗口表示对方还有多少空间可以被接受,通rwnd表示。发送方需要注意的是发送到连接中但未被确认的数据量 不能超过rwnd,这样可以保证不会使接收房接受缓存益处。 考虑到一个极端情况,如果发送方发现接受方的rwnd为0了,此时发送方不在发送数据,但接收方会慢慢消化自己的缓存,但接收方并不会主动通知发送方【只有接受方在有数据or有确认时才会给发送方发报文),这样就陷入了僵局,为了解决这个问题,tcp规定当rwnd为0后,发送方继续发送只有一个字节数据的报文段,这样将会打破僵局:接受方如果收到该报文并进行ack回报时将会告知发送方的rwnd已经不为0,一切就恢复过来了。 4 udp没有流量控制,所以接受方如果不能及时从接受缓冲中读取到数据(or读取不够快),会有缓存益处并丢失报文的问题。 拥塞控制 最后一个特征是拥塞控制,他的核心目标是为了高效地使用带宽但同时又不至于将网络阻塞到淹没。 1 拥塞窗口 cwnd:对一个tcp发送方向网络中能够发送的速率进行限制。结合前面说到的接受窗口,真实场景下tcp能够发送未确认的数据量不能超过 rwnd与cwnd的最小值。 这里有三个问题 tcp如何限制往一条连接上的发送速率? tcp如何感知到拥塞了? tcp采用何种算法进行限制速率f发送? 第一个问题 即调整cwnd的大小即可限制,第二个问题,tcp目前是通过超时以及收到三个冗余ack来进行主观判断。第三个问题是拥塞控制算法 目前tcp常见的拥塞控制算法是:慢启动+拥塞避免+快速恢复 慢启动:按照指数方式扩大cwnd的值,没收到一个ack就扩大一个wcnd,直到发送丢包or收到三个冗余ack, 接下来进入拥塞避免,将wcnd的值调整为当前值的一半,然后每次增加一个cwnd,直到拥塞。以此循环。 目前有一些改良优化的拥塞算法,如bbr等。 4最后谈下拥塞与公平 1tcp为了让道路更通畅,自觉地启用了拥塞控制,而udp没有,所以他是一种不合作的协议。 几个有趣的问题 1 syn flood以及如何避免? 在tcp三次握手时,client首先发送syn包保文,且附带自己的client_isn(序列号)[一般为了安全改isn为随机生成], server收到改syn后,一般来说会开始分配资源,包括缓存、socket、链接状态维护等资源,但如果client是恶意的发送大量的syn并不是想真实建立连接此时服务器将被大量的分配无效资源导致资源枯竭进而导致正常的连接服务不了。 解决办法:如果收到client的syn后,此时服务端并不确认该syn是否为真实有效的syn还是恶意的flood,为了区分,此时server并不急于为此分配资源,而是将生成一个序列号,此序列号为源ip/目的ip/源端口以及只有server内置知道的一个密钥而组成的散列后的值,然后给client回送过去syn+ack的包,注意这里服务端并没有记录任何关于连接的信息,只是回送了一个包【该包的序号为上面的散列值】,也就是并没有任何资源开销。接着,如果客户端会回送一个ack【如果不回送那么server也不损失任何】,服务端需要校验下,他从ack包的ack字段中提取之前的值,如果该值等于 源ip/源端口/目的ip+自己知道的蜜钥组成的散列值-1,则能够确认该ack是合法client回送过来的,此时server将开始为期分配资源。 这个解决办法的核心在于,服务端并不维持任何相关信息【没有资源开销也就没构成攻击】,这个信息是让client带过来的,所以有点类似cookied的使用,故而将这种解决办法称之为syn cookie。 2 mmap mmap用来扫描端口是否开启,mmap工作原理是发送一个syn包,如果收到了syn+ack说明该端口开了,如果收到一个rst,说明端口没开,而且还有进一步信息:说明mmap与被探测服务间 没有防火墙把这个syn丢掉。如果没有收到任何包,说明这之间有防火墙将syn丢了。 3 client在关闭连接时,time_wait状态为啥最后需要等待2个rtt后才能最终断掉 一是,client最后给server发送了ack(答复server发过来的fin),如果该ack丢了server会继续发fin,此时如果client提早退出则server收不到ack会处于非期望状态,所以要等一等。 二是,这个等待时间也是为了让该条连接上所有的“脏数据包”都消失掉,防止重新建立的连接使用了同样的端口而导致数据污染。 这也是为啥client端立即关闭的端口不能被使用的原因,当然这个time_wait一半都是主动断开的一方留住,在现实场景中也一般都留给了client。 四 ip层 应用层和运输层是处于网络边缘端上的行为,接下来ip层是网络核心的行为,包括交换机/路由器等。 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 1:53:08- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |