Wireshark分析艺术【读书总结】
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Wireshark分析艺术【读书总结】相关的知识,希望对你有一定的参考价值。
参考技术A[TOC]
性能分析三板斧之一:
【统计->捕获文件属性】
Statistics -> Summary,查看文件属性信息,如平均速度、包大小、包数等等
判断流量高低峰、是否过载
[图片上传失败...(image-7200fa-1541746330755)]
性能分析三板斧之二:
【分析->专家信息】
Wireshark ->Analyze -> Expert Infos -> Notes,查看抓包的统计信息
查看是否有Notes、Warnings、errors之类的信息,看看是否有相关警告和错误,判断网络质量、重传乱序等
[图片上传失败...(image-1e2d8b-1541746330755)]
性能分析三板斧之三:
【统计->服务响应时间】
statistics -> Service Response Time -> xxxxx(如:ONC-RPC -> Program:NFS)
查看各项操作的服务响应时间,判断是否过载
Edit->Preferences->Protocols->TCP,勾选 Relative Sequence Numbers
启用之前就是相对值了。
Statistics -> TCP StreamGraph -> TCP Sequence Graph(Stevens)
查看数据传输情况,如传输的是否均匀、是否有TCP Zero Windows之类的
字段含义就是wireshark的一些提示信息,也就是wireshark抓包的一些info信息,这些提示信息都是Info这一栏中体现。
如果某个包被标记提示 [Packer size limited during caputre] ,说明这个包没有抓全,可以进一步查看下面的frame信息。一般这个情况是抓包的姿势不对。某些操作系统中,tcpdump默认只抓取每个帧的前96个字节,因此tcpdump抓包的时候,可以通过 -s参数指定要抓取的字节数
如果wireshark发现被Ack的那个包没有抓到,就会提示 [TCP ACKed unseen segment] ,不过这个提示大部分情况都可以忽略。因为大都情况下,刚开始抓包的时候,都是只抓到了后面的Ack而没有抓到前面的ACK
TCP数据传输中,除了三次握手和四次握手之外,同一台机器发出的数据段应该是连续的,即后一个包的Seq等于前一个包的Seq+Len,正确情况都应该是这样;如果发现后一个包的Seq大于前一个包的Seq+Len,那么就说明中间丢了一段数据,如果丢失的数据在整个网络包中都找不到,wireshark就会提示 [TCP Previous segment not captured] ,
出现这种情况的两个可能性:
TCP数据传输中,除了三次握手和四次握手之外,同一台机器发出的数据段应该是连续的,即后一个包的Seq等于前一个包的Seq+Len,正确情况都应该是这样;或者说后一个包的Seq应该会大于等于前一个包的Seq+Len,如果wireshark发现后一个包的Seq小于前一个包的Seq+Len,那么就认为是乱序了,就会提示 [TCP Out-of-Order] 。
一般而言,小跨度的乱序影响不大,如果是大跨度的乱序则会导致快速重传。举例如下,如果一个包的顺序是1、2、3、4、5被打乱成2、1、3、4、5则属于小跨度乱序,影响不大;如果被打乱成2、3、4、5、1,则会触发足够多的Dup ACK,从而导致1号包的重传。
当乱序或者丢包发生时,接收方就会收到一些Seq号比期望值大的包,TCP协议每收到一个这种包就会ACK一次期望的Seq值,通过这个方式告知发送方,因此就产生了一些重复的Ack。Wireshark抓到这些重复的Ack就会提示 [TCP Dup ACK] .
当发送方连续收到3个或者以上 [TCP Dup ACK] 时,就意识到之前发的包可能丢了,于是根据RFC的规定就会开始快速重传。 [TCP Dup ACK] 是接收方回应给发送方的,因此发送方就能够感知到并当连续收到3个以上的时候就开启快速重传。
快重传算法规定,发送方只要一连收到3个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计数器时间到期。
如果一个包真的丢了,又没有后续包可以在接收方触发[Dup Ack],那么就不会开启快速重传,这种情况发送方只能等到超时后再发送重传,超时重传的包就会被wireshark标记并提示 [TCP Retransmission]
TCP 超时与重传应该是 TCP 最复杂的部分之一,超时重传是 TCP 保证可靠传输的基础。当 TCP 在发送数据时,数据和 ack 都有可能会丢失,因此,TCP 通过在发送时设置一个定时器来解决这种问题。如果定时器溢出还没有收到确认,它就重传数据。关键之处就在于超时和重传的策略,需要考虑两方面:
在 Linux 较高的内核版本中,比如 3.15 中,已经有了至少 9 个定时器:超时重传定时器,持续定时器,ER延迟定时器,PTO定时器,ACK延迟定时器,SYNACK定时器,保活定时器,FIN_WAIT2定时器,TIME_WAIT定时器。
TCP包中“win=xxx”代表接收窗口的大小,表示这个包的发送方当前还有多少缓冲区可以接受数据。当wireshark发行一个包中的“win=0”时,就会标记提示 [TCP zerowindow] ,表示缓冲区已经满了,无法再接收数据了。
一般的,在缓冲区满之前,窗口大小应该是逐渐减小的过程。
如果一个包的发送方已经把对方所声明的接收窗口大小耗尽了,就会被wireshark标记为 [TCP window Full] 。比如某一端在握手时声明自己的接收窗口只有65535,也就意味着对端最多只能给他发送65535字节的数据而无需确认,即“在途字节数”最多只能是65535,当wireshark计算出对端已经有65535字节未被确认时,就会发生这个提示。
[TCP window Full]和上面的[TCP zerowindow]比较容易混淆,前者表示这个包的发送方暂时没有办法再发送数据了;后者表示这个包的发送方没有办法再接收数据了;两者都会意味着要暂停数据传输
只有在Edit->Preferences->Protocols->TCP菜单里启用了 Allow sub dissector to reassemble TCP streams 后,才有可能收到这个提示。这个表示可以把属于同一个应用层PDU的TCP包虚拟的集中起来
只有在Edit->Preferences->Protocols->TCP菜单里关闭了 Allow sub dissector to reassemble TCP streams 后,才有可能收到这个提示。
(Fragment reasembly time execeeded)表示这个包的发送方之前收到了一些分片,但是由于某些原因导致迟迟无法组装起来。
比如传输过程中有一些分片被丢包了,那么接收方就无法组装起来,然后就通过这个ICMP的方式告知发送方
ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.
抓包显示的控制字段形态如下:
[SYN] : 建立连接、发起包
[FIN] : 关闭连接、结束包
[PSH] : DATA数据传输
[ACK] : ACK回应
[RST] : RESET、连接重置
另外两个常用字段:
[Len] :数据包长度
[Seq] :数据包序列号
ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,如果只是单个的一个SYN,它表 示的只是建立连接
当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接
当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接
对应http而言,一般就是request->reponse,一问一答。但对应TCP而言,并不一定每个包都会ACK。TCP的ACK是一种累积的ACK,也就是表示在我这个ACK之前的所有其他ACK都已经确认收到了。
比如,97号包的ACK=65701,96号包的Seq+Len=64273+1428=65701,那么就是表示97号的ACK是对96号的回应,也就是96号之前的其他没有被显示ACK的包,其实都已经通过97号包ACK了,这样发送方也就知道了在96号之前发出去的所有包对方都已经收到并ACK了。
Protocol = ARP
Source 和 Destination 都是MAC地址格式如 00:60:48:ff:12:31
抓包分析中,如果网络不通,发出去收不到ACK等等之类的,要再进一步看看每个包的MAC地址是否正确,反之有多个MAC地址导致的一些问题
一些实战经验告诉我们, Wireshark ->Analyze -> Expert Info -> Notes 统计中的重传率如果超过了0.1%,就需要采取一些措施了。但是现实网络环境下,要低于0.01%的重传是基本不可能的。
如果tcp对每个数据包都发送一个ack确认,那么只是一个单独的数据包为了发送一个ack代价比较高,所以tcp会延迟一段时间,如果这段时间内有数据发送到对端,则捎带发送ack,如果在延迟ack定时器触发时候,发现ack尚未发送,则立即单独发送;
延迟ACK好处:
(1) 避免糊涂窗口综合症;
(2) 发送数据的时候将ack捎带发送,不必单独发送ack;
(3) 如果延迟时间内有多个数据段到达,那么允许协议栈发送一个ack确认多个报文段;
试想如下典型操作,写-写-读,即通过多个写小片数据向对端发送单个逻辑的操作,两次写数据长度小于MSS,当第一次写数据到达对端后,对端延迟ack,不发送ack,而本端因为要发送的数据长度小于MSS,所以nagle算法起作用,数据并不会立即发送,而是等待对端发送的第一次数据确认ack;这样的情况下,需要等待对端超时发送ack,然后本段才能发送第二次写的数据,从而造成延迟;
使用TCP套接字选项TCP_NODELAY可以关闭套接字选项;
如下场景考虑关闭Nagle算法:
(1) 对端不向本端发送数据,并且对延时比较敏感的操作;这种操作没法捎带ack;
(2) 如上写-写-读操作;对于此种情况,优先使用其他方式,而不是关闭Nagle算法:
TCP和UDP的区别如TCP是可靠的、UDP是不可靠的,但是实际中的表现是何为可靠?何为不可靠?具体协议的ACK有何区别?
不管对于TCP还是UDP,都可能会被分片,这是由于以太网的MSS决定的;不同在于分片传输的处理:
语音通话的场景在于不能接受延迟,但是可以接受音质稍差。这样的话,UDP传输的时候,如果有些包丢失,应用层可以选择忽略并继续传输其他包,丢到一些包只会影响到音质,但是保证了流畅性。TCP而言,会重传每个包,只要丢包就重传,这样就会导致有一定的延迟,在语音中如果有延迟则并不可取。
因此,TCP和UDP,各自有各自的适合场景。 语音、视频中,UDP更合适,像声网、linphone等都是UDP去处理音视频。 基础、核心协议交互中必须采用TCP。
TCP在传输过程都需要往返时间来确认也就是ACK,而UDP则无需确认,那么UDP的效率一定比TCP高吗?这个是不一定的,虽然UDP可以一直往外不停的发包,不用等待ACK;但是TCP有发送窗口的存在,如果发送窗口小,并没有占满带宽,那么肯定受到往返时间的约束使得效率稍低,但是如果只要窗口足够大并且合适,跑满带宽,那么TCP也是可以不受往返时间的约束而源源不断的传输数据。
举例:马路上只有一辆车来回跑去拉货,回程过程相当于空跑(回程相当于TCP的ACK),这样TCP的效率当然低。但是如果在不拥塞的情况下,尽量提高车辆数量,是的马路上的车被刚好充满,这样总体的传输效率提高了,并且回程的ACK也不受影响。
分组交换,把大的数据分割成小包,这样可以实现链路共享,而不至于因为某一方阻塞所有。既然要分割成小包,那么必然要确定一个最大的包大小,这个就是MTU(Maximum Transmission Unit)最大传输单位,值为1500字节。如果除去20个字节的包头结构,那么一个IP包最大的包大小为1500-20=1480字节。如果要传输的数据块超过1480字节,那么网络层就会将其分片处理,封装为多个网络包传输。对于TCP而言,TCP协议层会主动把数据分成小段后再交给网络层,TCP的最大分段大小称之为MSS(Maximum Segment Size),这个MSS被设置为MTU减去IP头和TCP头之后的大小,这样刚好可以满足一个MTU。因为UDP没有MSS的概念,因此就只能交给网络层去处理分片了。
但是需要注意的是,目前有些网络是Jumbo Frame(巨帧)或者PPPOE这样的设备,那么他们的MTU则不是1500字节。目前发送方并没有一个好的机制来确定最佳分片大小,应该尽量使得网络中的设备的MTU保持一致。如果网络中的设备的MTU不一致,那么TCP协议如何适配MTU呢?我们知道TCP建连的时候必须要先进行三次握手,TCP在前两个握手包中会相互声明自己的MSS。如果client端声明自己的MSS=8960(巨帧),server端申明自己的MSS=1460,那么client在三次握手后就知道了server端的MSS,因此当client想要发送大于server端MSS的包的时候就会主动将自己的MSS降低为server端的MSS大小,从而适配接收方的MTU,可见,TCP协议层做了非常多的优化和处理
既然有分片,那么接收方必然要进行分片重组,通过抓包工具可以得知,分片的每个包都包含了 off=xxx,ID=xxx 这样的信息,接收方会把ID相同的分片按照off偏移量进行重组。那么接收方又如何得知那个包才是最后的分片呢?然后什么时候开始重组呢?这里就在于最后一个分片包有一个特殊的Flag,叫 More fragment = 0 ,抓包中的表现形式是 ..0. ... = More fragment: Not set ,这个就表示它是最后一个分片,然后可以开始重组包了。如果是其他分片包,形如 ..1. ... = More fragment: set 则表示接收方需要缓存,等待其他分片传输完成
如果client端的MTU=9000,server端的MTU=1500,那么当client请求server端的时候,client的包经过路由器时候,要么就被丢包,要么就被分片。如果这个巨帧包在网络层携带了DF(Don\'t fragment)标志则被丢弃(设置则表示不允许分片),如果没有设置则进行分片传输。需要注意的是,这种情况下如果丢包了重传还是会被丢弃,就成了黑洞了。
测试中,可以通过ping命令模拟这样的情况:
-f 参数表示设置DF标志
-l 参数表示请求字节
当请求字节设置为1472的时候,因为ICMP头部为8字节、IP头为20字节,因此1472+8+20=1500,刚好是一个MTU,因此可以ping成功。但是第二个1473+8+20=1501字节超过MTU了,又因为设置了DF标志表示不允许分片,因此传输失败,一般这样的情况下,路由器会回复 Packet needs to be fragmented but DF set 。
抓包的时候,如果发现一直重传,某个某些相对较大的包(查看Len值)才重传,那么可以通过 ping xxx.xxx.xxx.xxx -l [Len] -f 值进行测试验证,通过这个ping指定的[Len]的大小变化来寻得规律,可能就会发现网络上某个设备的MTU并非1500,这样导致了超过这个就重传的现象。
client 和 server端直接一定有交换机、路由器等设备,如果server端是万兆网卡,client端是千兆网卡,就有可能使得server端发送过快导致数据堵在交换机上,从而交换机在堵满之后发生丢包。 但是一般而言,server端的带宽本应该要大于client端才算合理,为了避免拥塞,因此需要有一种流控机制,允许交换机在过载时告知server端放慢速度或者暂停传输。
有一种“暂停帧”,就能够满足这样的需求:当交换机的缓冲区即将被填满时发送给server端一个暂停帧,当server端等待一会儿再发,这样就可以避免溢出丢包,也避免丢包后的重传。server端等待多久则由暂停帧中的pause_time指定,这样server端在等待pause_time后才会开始继续发送。当然交换机还可以给server端发送一个pause_time=0的暂停帧,告知server端,我已经消化完了,可以立即发送了。
注意,这的流控和TCP的流控是不一样的
《JavaScript DOM编程艺术(第二版)》读书总结
这本书是一本很基础的书,但对于刚入前端不久的我来说是一本不错的书,收获还是很大的,对一些基础的东西理解得更加透彻了。
1.DOM即document object model的缩写,文档对象模型,JavaScript做的就是对DOM的操作,或者说对节点(node)的操作。
2.js中DOM、this这是都是对象,有属性有方法。
3.document对象有body属性,所以可以直接写成document.body,无需再获取body元素(document.getElementsByTagName("body")[0]),createElement创建出来的节点也是一个对象。
4.取得当前页面的URL,window.location.href。
5.循环、判断不会形成作用域,只有函数才会形成,比如说下面这个代码:
function fn(){
if(1==1){
alert(1)
return false
alert(2)
}
alert(3)
}
fn()
以前认为1和3都会弹出,其实不是,这里只会弹出1,虽然if语句中有大括号{ },但它不会有形成作用域的作用,只有函数才会形成,所以在函数fn里return false后面的代码都不会被执行。
6.书中四个比较有用的原生js函数。
①我们都知道如果在body元素前加入script标签引入js,那么就必须写上:
window.onload= function (){
}
意思是等文档结构加载完毕再加载这个函数里面的代码,不然就无法获取DOM元素。书中给了另外一种不写这个函数的方法,将要执行的函数当做addLoadEvent函数的参数即可 :
//onload事件共享函数
function addLoadEvent(func){
var oldonload=window.onload;
if(typeof window.onload !="function"){
window.onload=func;
}else{
window.onload = function (){
oldonload();
func();
}
}
}
②原生js没有提供insertAfter方法,只有insertBefore方法,封装insertAfter函数,参数是DOM对象:
function insertAfter(newElement,targetElement){
var parent = targetElement.parentNode;
if(parent.lastChild == targetElement){
parent.appendChild(newElement);
}else{
parent.insertBefore(newElement,targetElement.nextSibling);
}
}
③动画函数
//动画函数
function moveElement(elementID,final_x,final_y,interval){
if(!document.getElementById) return false;
if(!document.getElementById(elementID)) return false;
var elem=document.getElementById(elementID);
if(elem.movement){
clearTimeout(elem.movement);
}
if(!elem.style.top){
elem.style.top = "0px"
}
if(!elem.style.left){
elem.style.left = "0px"
}
var xpos = parseInt(elem.style.left);
var ypos = parseInt(elem.style.top);
var dist = 0;
if(xpos == final_x && ypos == final_y){
return true;
}
if(xpos < final_x){
dist = Math.ceil((final_x - xpos)/10);
xpos = xpos + dist;
}
if(xpos > final_x){
dist = Math.ceil((final_x - xpos)/10);
xpos = xpos - dist;
}
if(ypos < final_y){
dist = Math.ceil((final_y - ypos)/10);
ypos = ypos + dist;
}
if(ypos > final_y){
dist = Math.ceil((final_y - ypos)/10);
ypos = ypos - dist;
}
elem.style.left = xpos + "px";
elem.style.top = ypos + "px";
var repeat = "moveElement(‘"+elementID+"‘,"+final_x+","+final_y+","+interval+")";
elem.movement = setTimeout(repeat,interval);
}
用法如: moveElement("div",300,300,20),第一个参数元素id,第二个第三个参数是元素最终的位置,第四个参数是时间间距。
④给一个元素添加类名的函数
//添加类名addClass函数
function addClass(element,value){
if(!element.className){
element.className = value;
}else{
newClassName = element.className;
newClassName+= " ";
newClassName+= value;
element.className = newClassName;
}
}
一同事看我读这本书,总是对我讲“看书没有用,你还是会忘记的”,我其实听他说这话好几次挺烦的,我没有反驳他,我觉得这种话题真的不值得我去反驳。
以上是关于Wireshark分析艺术【读书总结】的主要内容,如果未能解决你的问题,请参考以下文章