用了TCP协议,就一定不会丢包吗?( 四 )


用了TCP协议,就一定不会丢包吗?

文章插图
 
send非阻塞
当接受缓冲区满了 , 事情就不一样了 , 它的TCP接收窗口会变为0 , 也就是所谓的零窗口 , 并且会通过数据包里的win=0 , 告诉发送端 , "球球了 , 顶不住了 , 别发了" 。一般这种情况下 , 发送端就该停止发消息了 , 但如果这时候确实还有数据发来 , 就会发生丢包 。
用了TCP协议,就一定不会丢包吗?

文章插图
 
recv_buffer丢包
我们可以通过下面的命令里的TCPRcvQDrop查看到有没有发生过这种丢包现象 。
cat /proc/net/netstatTcpExt: SyncookiesSent TCPRcvQDrop SyncookiesFailedTcpExt: 015760116但是说个伤心的事情 , 我们一般也看不到这个TCPRcvQDrop , 因为这个是5.9版本里引入的打点 , 而我们的服务器用的一般是2.x~3.x左右版本 。你可以通过下面的命令查看下你用的是什么版本的linux内核 。
# cat /proc/versionLinux version 3.10.0-1127.19.1.el7.x86_64 
两端之间的网络丢包前面提到的是两端机器内部的网络丢包 , 除此之外 , 两端之间那么长的一条链路都属于外部网络 , 这中间有各种路由器和交换机还有光缆啥的 , 丢包也是很经常发生的 。
这些丢包行为发生在中间链路的某些个机器上 , 我们当然是没权限去登录这些机器 。但我们可以通过一些命令观察整个链路的连通情况 。
 
ping命令查看丢包比如我们知道目的地的域名是 baidu.com 。想知道你的机器到baidu服务器之间 , 有没有产生丢包行为 。可以使用ping命令 。
用了TCP协议,就一定不会丢包吗?

文章插图
 
ping查看丢包
倒数第二行里有个100% packet loss , 意思是丢包率100% 。
但这样其实你只能知道你的机器和目的机器之间有没有丢包 。
那如果你想知道你和目的机器之间的这条链路 , 哪个节点丢包了 , 有没有办法呢?
有 。
 
mtr命令mtr命令可以查看到你的机器和目的机器之间的每个节点的丢包情况 。
像下面这样执行命令 。
用了TCP协议,就一定不会丢包吗?

文章插图
 
mtr_icmp
其中-r是指report , 以报告的形式打印结果 。
可以看到Host那一列 , 出现的都是链路中间每一跳的机器 , Loss的那一列就是指这一跳对应的丢包率 。
需要注意的是 , 中间有一些是host是??? , 那个是因为mtr默认用的是ICMP包 , 有些节点限制了ICMP包 , 导致不能正常展示 。
我们可以在mtr命令里加个-u , 也就是使用udp包 , 就能看到部分???对应的IP 。
用了TCP协议,就一定不会丢包吗?

文章插图
 
mtr-udp
把ICMP包和UDP包的结果拼在一起看 , 就是比较完整的链路图了 。
还有个小细节 , Loss那一列 , 我们在icmp的场景下 , 关注最后一行 , 如果是0% , 那不管前面loss是100%还是80%都无所谓 , 那些都是节点限制导致的虚报 。
但如果最后一行是20% , 再往前几行都是20%左右 , 那说明丢包就是从最接近的那一行开始产生的 , 长时间是这样 , 那很可能这一跳出了点问题 。如果是公司内网的话 , 你可以带着这条线索去找对应的网络同事 。如果是外网的话 , 那耐心点等等吧 , 别人家的开发会比你更着急 。


推荐阅读