08 | 工欲善其事必先利其器:学会使用各种工具
下载APP
关闭
渠道合作
推荐作者
08 | 工欲善其事必先利其器:学会使用各种工具
2019-08-19 盛延敏 来自北京
《网络编程实战》
课程介绍
讲述:冯永吉
时长10:33大小9.66M
你好,我是盛延敏,这里是网络编程实战第 8 讲,欢迎回来。
上一讲我们讲到了本地套接字,加上前面介绍的 TCP、UDP 套接字,你会发现我们已经比较全面地接触了套接字。
其实在平常使用套接字开发和测试过程中,我们总会碰到这样或那样的问题。学会对这些问题进行诊断和分析,其实需要不断地积累经验。而 Linux 平台下提供的各种网络工具,则为我们进行诊断分析提供了很好的帮助。在这一讲里,我将会选择几个重点的工具逐一介绍。
必备工具: ping
这个命令我想大家都不陌生,“ping”这个命名来自于声呐探测,在网络上用来完成对网络连通性的探测,这个命名可以说是恰如其分了。
在上面的例子中,我使用 ping 命令探测了和新浪网的网络连通性。可以看到,每次显示是按照 sequence 序列号排序显示的,一并显示的,也包括 TTL(time to live),反映了两个 IP 地址之间传输的时间。最后还显示了 ping 命令的统计信息,如最小时间、平均时间等。
我们需要经常和 Linux 下的 ping 命令打交道,那么 ping 命令的原理到底是什么呢?它是基于 TCP 还是 UDP 开发的?
都不是。
其实,ping 是基于一种叫做 ICMP 的协议开发的,ICMP 又是一种基于 IP 协议的控制协议,翻译为网际控制协议,其报文格式如下图:
ICMP 在 IP 报文后加入了新的内容,这些内容包括:
类型:即 ICMP 的类型, 其中 ping 的请求类型为 8,应答为 0。
代码:进一步划分 ICMP 的类型, 用来查找产生错误的原因。
校验和:用于检查错误的数据。
标识符:通过标识符来确认是谁发送的控制协议,可以是进程 ID。
序列号:唯一确定的一个报文,前面 ping 名字执行后显示的 icmp_seq 就是这个值。
当我们发起 ping 命令时,ping 程序实际上会组装成如图的一个 IP 报文。报文的目的地址为 ping 的目标地址,源地址就是发送 ping 命令时的主机地址,同时按照 ICMP 报文格式填上数据,在可选数据上可以填上发送时的时间戳。
IP 报文通过 ARP 协议,源地址和目的地址被翻译成 MAC 地址,经过数据链路层后,报文被传输出去。当报文到达目的地址之后,目的地址所在的主机也按照 ICMP 协议进行应答。之所以叫做协议,是因为双方都会遵守这个报文格式,并且也会按照格式进行发送 - 应答。
应答数据到达源地址之后,ping 命令可以通过再次解析 ICMP 报文,对比序列号,计算时间戳等来完成每个发送 - 应答的显示,最终显示的格式就像前面的例子中展示的一样。
可以说,ICMP 协议为我们侦测网络问题提供了非常好的支持。另外一种对路由的检测命令 Traceroute 也是通过 ICMP 协议来完成的,这里就不展开讲了。
基本命令: ifconfig
很多熟悉 Windows 的同学都知道 Windows 有一个 ipconfig 命令,用来显示当前的网络设备列表。事实上,Linux 有一个对应的命令叫做 ifconfig,也用来显示当前系统中的所有网络设备,通俗一点的说,就是网卡列表。
我稍微解释一下这里面显示的数据。
上面这段表明这是一个以太网设备,MAC 地址为 02:54:ad:ea:60:2e。
这里显示的是网卡的 IPv4 和 IPv6 地址,其中 IPv4 还显示了该网络的子网掩码以及广播地址。
在每个 IPv4 子网中,有一个特殊地址被保留作为子网广播地址,比如这里的 10.0.2.255 就是这个子网的广播地址。当向这个地址发送请求时,就会向以太网网络上的一组主机发送请求。
通常来说,这种被称作广播(broadcast)的技术,是用 UDP 来实现的。
这里显示的是网卡的状态,MTU 是最大传输单元的意思,表示的是链路层包的大小。1500 表示的是字节大小。
Metric 大家可能不知道是干啥用的,这里解释下,Linux 在一台主机上可以有多个网卡设备,很可能有这么一种情况,多个网卡可以路由到目的地。一个简单的例子是在同时有无线网卡和有线网卡的情况下,网络连接是从哪一个网卡设备上出去的?Metric 就是用来确定多块网卡的优先级的,数值越小,优先级越高,1 为最高级。
netstat 和 lsof:对网络状况了如指掌
在平时的工作中,我们最常碰到的问题就是某某进程对应的网络状况如何?是不是连接被打爆了?还是有大量的 TIME_WAIT 连接?
netstat 可以帮助我们了解当前的网络连接状况,比如我想知道当前所有的连接详情,就可以使用下面这行命令:
可能的结果为:
netstat 会把所有 IPv4 形态的 TCP,IPV6 形态的 TCP、UDP 以及 UNIX 域的套接字都显示出来。
对于 TCP 类型来说,最大的好处是可以清楚地看到一条 TCP 连接的四元组(源地址、源端口、目的地地址和目的端口)。
例如这里的一条信息:
它表达的意思是本地 127.0.0.1 的端口 52464 连上本地 127.0.0.1 的端口 2379,状态为 ESTABLISHED,本地进程为 etcd,进程为 3496。
这在实战分析的时候非常有用,比如你可以很方便地知道,在某个时候是不是有很多 TIME_WAIT 的 TCP 连接,导致端口号被占用光,以致新的连接分配不了。
当然,我们也可以只对 UNIX 套接字进行筛查。
UNIX 套接字的结果稍有不同,最关键的信息是 Path,这个信息显示了本地套接字监听的文件路径,比如这条:
这其实就是大名鼎鼎的 Docker 在本地套接字的监听路径。/var/run/docker.sock 是本地套接字监听地址,dockerd 是进程名称,1400 是进程号。
netstat 命令可以选择的参数非常之多,这里只关注了几个简单的场景,你可以通过帮助命令或者查阅文档获得更多的信息。
lsof 的常见用途之一是帮助我们找出在指定的 IP 地址或者端口上打开套接字的进程,而 netstat 则告诉我们 IP 地址和端口使用的情况,以及各个 TCP 连接的状态。Isof 和 netstst 可以结合起来一起使用。
比如说,我们可以通过 lsof 查看到底是谁打开了这个文件:
下面这张图显示了是 dockerd 打开了这个本地文件套接字:
lsof 还有一个非常常见的用途。如果我们启动了一个服务器程序,发现这个服务器需要绑定的端口地址已经被占用,内核报出“该地址已在使用”的出错信息,我们可以使用 lsof 找出正在使用该端口的那个进程。比如下面这个代码,就帮我们找到了使用 8080 端口的那个进程,从而帮助我们定位问题。
抓包利器: tcpdump
tcpdump 这样的抓包工具对于网络编程而言是非常有用的,特别是在一些“山重水复疑无路”的情形下,通过 tcpdump 这样的抓包工具,往往可以达到“柳暗花明又一村”的效果。
tcpdump 具有非常强大的过滤和匹配功能。
比如说指定网卡:
再比如说指定来源:
我们再来一个复杂一点的例子。这里抓的包是 TCP,且端口是 80,包来自 IP 地址为 192.168.1.25 的主机地址。
如果我们对 TCP 协议非常熟悉,还可以写出这样的 tcpdump 命令:
这里 tcp[13:1]表示的是 TCP 头部开始处偏移为 13 的字节,如果这个值为 2,说明设置了 SYN 分节,当然,我们也可以设置成其他值来获取希望类型的分节。注意,这里的偏移是从 0 开始算起的,tcp[13]其实是报文里的第 14 个字节。
tcpdump 在开启抓包的时候,会自动创建一个类型为 AF_PACKET 的网络套接口,并向系统内核注册。当网卡接收到一个网络报文之后,它会遍历系统中所有已经被注册的网络协议,包括其中已经注册了的 AF_PACKET 网络协议。系统内核接下来就会将网卡收到的报文发送给该协议的回调函数进行一次处理,回调函数可以把接收到的报文完完整整地复制一份,假装是自己接收到的报文,然后交给 tcpdump 程序,进行各种条件的过滤和判断,再对报文进行解析输出。
下面这张图显示的是 tcpdump 的输出格式:
首先我们看到的是时间戳,之后类似 192.168.33.11.41388 > 192.168.33.11.6443 这样的,显示的是源地址(192.168.33.11.41388)到目的地址(192.168.33.11.6443);然后 Flags [ ]是包的标志,[P]表示是数据推送,比较常见的包格式如下:
[S]:SYN,表示开始连接
[.]:没有标记,一般是确认
[P]:PSH,表示数据推送
[F]:FIN,表示结束连接
[R] :RST,表示重启连接
我们可以看到最后有几个数据,它们代表的含义如下:
seq:包序号,就是 TCP 的确认分组
cksum:校验码
win:滑动窗口大小
length:承载的数据(payload)长度 length,如果没有数据则为 0
此外,tcpdump 还可以对每条 TCP 报文的细节进行显示,让我们可以看到每条报文的详细字节信息。这在对报文进行排查的时候很有用。
小结
本章我讲述了一些常见的网络诊断工具,这些工具需要你了解之后活学活用。用好它们,对加深网络编程的理解,以及对问题情况进行排查等都有非常大的帮助。
我再来总结一下这几个命令的作用:
ping 可以用来帮助我们进行网络连通性的探测。
ifconfig,用来显示当前系统中的所有网络设备。
netstat 和 lsof 可以查看活动的连接状况。
tcpdump 可以对各种奇怪的环境进行抓包,进而帮我们了解报文,排查问题。
思考题
最后给大家留两个思考题。
本章我讲到了强大的抓包工具 tcpdump,你知道 tcpdump 这个工具还可以对 UDP 包进行抓包处理吗?你不妨尝试一下。
另外,netstat 输出时,监听状态的套接字所对应的 Foreign Address 显示的 *.* 表示的是什么意思呢?
欢迎你在评论区写下你的思考,我会和你一起交流,也欢迎你把这篇文章分享给你的朋友或者同事,一起讨论下这几个工具。
分享给需要的人,Ta购买本课程,你将得18元
生成海报并分享
赞 22
提建议
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
上一篇
07 | What? 还有本地套接字?
下一篇
09丨答疑篇:学习网络编程前,需要准备哪些东西?
精选留言(31)
- xindoo2019-08-19iftop命令可以查网络io大户共 1 条评论59
- 许童童2019-08-19tcpdump可以抓UDP,很简单 指定端口就可以了。 tcpdump还可以导出文件pcap,放到wireshark中进一步分析。 Foreign Address 显示的 *.* 表示的是什么意思呢? 这个套接字正在监听端口等待连接进来,允许任何地址、任何端口来建立连接。展开共 3 条评论31
- 一步2019-08-20对于 ping 的最后统计信息中 rtt min/avg/max/mdev = 4.512/4.579/4.647/0.078 ms 中的 mdev 时间是什么意思的?
作者回复: 这个值我也没注意过,看了介绍是说mdev 就是 Mean Deviation 的缩写,它表示这些 ICMP 包的 RTT 偏离平均值的程度,这个值越大说明你的网速越不稳定。
共 2 条评论12 - 剑衣清风2019-08-19tcpdump 可以结合 wireshark,也就是把抓到的协议包保存成 cap 格式的,然后在 windows 上点击查看更加形象 tcpdump host 10.1.11.133 and udp port 5060 -v -w gw.cap【写成 wireshark 可读取的】10
- icejoywoo2019-11-02ss可以替代netstat么,netstat有时候非常慢,ss速度很快
作者回复: 可以的,作为一个老程序员,ss是我刚刚接触到的,学习了。
6 - jay2020-03-30文中这句语: 即 ICMP 的类型, 其中 ping 的请求类型为 0,应答为 8。描述有误,请求类型为8,应答为0。 Type: 8 (Echo (ping) request) Type: 0 (Echo (ping) reply)
作者回复: 感谢斧正,已经修改,待提交。
共 2 条评论5 - 明键2019-11-27IPv6的地址不是128位吗,为什么我数ifconfig的输出只有12字节?还有四字节到哪里去了呢?
作者回复: IPV6的地址格式为X:X:X:X:X:X:X:X,一共8个X,其中每个X表示地址中的16b,以十六进制表示。 在某些情况下,一个IPv6地址中间可能包含很长的一段0,可以把连续的一段0压缩为“::”。 所以,看看你的地址里是不是有::哦。
共 2 条评论5 - 哦哟哟哟哟2019-08-19麻烦老师解答下。前面ifconfig命令关于网卡优先级的metric=1表示优先级最高、示例中三张网卡优先级都是1、那如何进行选择呢
作者回复: 看你应用程序绑定到哪个网卡设备和Ip了
共 2 条评论5 - 钱2019-11-22小结 ping 可以用来帮助我们进行网络连通性的探测。 ifconfig,用来显示当前系统中的所有网络设备。 netstat 和 lsof 可以查看活动的连接状况。 tcpdump 可以对各种奇怪的环境进行抓包,进而帮我们了解报文,排查问题。 iftop命令可以查网络io大户 arp router ss展开共 1 条评论4
- 超大红细胞2020-01-05tcpdump 抓取 1400 端口 UDP 报文并保存: tcpdump -i ens33 udp port -w ./udp.cap
作者回复: 学习了
共 2 条评论3 - 晚风·和煦2020-02-11老师,accept是发生在三次握手之后吗?😂
作者回复: 在程序角度来说,accept函数表示的是三次握手的过程,如果从accept返回,表示三次握手成功,连接已经建立。
共 2 条评论2 - 极客雷2019-10-22ifconfig、netstat都是比较偏老的、不再维护的命令,为啥不与时俱进讲一下iproute2系列的命令
作者回复: 这些命令在平时的trouleshooting还是很有用处的,毕竟还不能在生产环境都换成Linux 4/5版本吧。
2 - null2021-04-09如果对方禁ping 了,还有其他方法能测试与对方服务器的连通性么?
作者回复: ping都不通了,可以认为对方服务器真的下线了
共 3 条评论1 - NEVER SETTLE2020-10-31老师,我用CLion编写代码时,有明显的语法错误,结果没有提示出来(波浪线等等)
作者回复: 正常啊,工具也不是万能的。不过很好奇,什么样的语法错误逃脱了CLion的火眼金睛。
1 - dll2022-07-29 来自北京RX packets:7951 errors:0 dropped:0 overruns:0 frame:0 TX packets:4123 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:5081047 (5.0 MB) TX bytes:385600 (385.6 KB) _________ RX TX 是什么呢。我看到文里没有解释展开共 1 条评论
- gecko2022-07-14netstat netstat -x -alepn yes netstat Socket -x -alepn no
- null2021-03-19macbook 下,也是使用 wireshark 配合 tcpdump 文件一起么?
作者回复: mac是可以使用这两个工具的。
- null2021-03-18cni0(1450)、enp0s3(1500)、docker0(1500)这三者的 MTU 为啥不一样,是协议栈的不同么? 这三个网卡的 Metric 都为 1,最高级,那最终选择哪一个网卡设置呀? 谢谢老师!
作者回复: 选择哪个网卡,有多个因素会决定,一个可能的因素是系统路由表,比如docker0的地址是172.17.0.1,走172.17.0.0/16的地址就会通过docker0。
- Geek_8593e52020-09-03老师说的,类型:即 ICMP 的类型, 其中 ping 的请求类型为 0,应答为 8。我实际测了下,应答为0,请求为8?
作者回复: 你是对的,我已更改文稿。
- 你好2020-04-08🙋,老师我有问题: 前面文章中提到过:使用 INADDR_ANY,一台机器有两块网卡,IP 地址分别是 202.61.22.55 和 192.168.1.11,那么向这两个 IP 请求的请求包都会被我们编写的应用程序处理。那如果优先级相同是走哪一个呢? 那服务器/客户端绑定端口的时候如何指定使用哪个网卡进行绑定呢?展开
作者回复: 应该是随机的吧,没有什么优先级;一般我们多用ANY_ADDR来做,本身就不想限制是哪块网卡或者IP地址。