前言

在做Android开发时,有时我们需要知道设备的网络好不好,光看手机上的信号格数是不准确的,比如在广州南站,人那么多,如果带宽不够的话,虽然你看着信号是满格的,但是网速也会很慢,有些地方,人少,信号也满格,但是网速也慢,所以不能光看信号强度,还是得通过ping命令来看网速比较可靠。

在Android的实际开发中,我们公司开发了音视频通讯App,安装在了客户的设备上,客户说,哎,怎么看不到视频啊,你这App不行啊,每次遇到这种问题我们就会说,是你的网络不行啊。啊哈,很搞笑,一有问题我们就会说是客户的网络不好导致的,但是每次你这么说的话也不太好啊,你要拿出证据来啊,客户说他信号明明是满格的呀!所以解决方案就是在App上面增加ping的功能,这样看网络好不好就比较有理有据了。当然,我们也可以远程ping,就是通过网络给客户的app发命令,app收到命令后就开始ping,ping完之后把结果通过网络再传到我们这边的app上,这样我们就可以远程查看客户的网络情况了。

ping的含义

来自百度百科,ping (Packet Internet Groper)是一种因特网包探索器,用于测试网络连接量的程序 。Ping是工作在 TCP/IP网络体系结构中应用层的一个服务命令, 主要是向特定的目的主机发送 ICMP(Internet Control Message Protocol 因特网报文控制协议)Echo 请求报文,测试目的站是否可达及了解其有关状态。

ping用于确定本地主机是否能与另一台主机成功交换(发送与接收)数据包,再根据返回的信息,就可以推断TCP/IP参数是否设置正确,以及运行是否正常、网络是否通畅等。

Windows中的ping命令

Windows中的ping命令可以通过 -l 设置发送数据包的大小,通过 -w 可以设置超时时间,示例如下:

如上图,-l 128设置了发送的数据包为128 bytes,不设置的话默认是32 bytes,-w 4000设置了超时时间为4000毫秒(不写的话,默认好像超时也是4000毫秒),Windows默认是ping四次,所以出现了4行的超时(Request timed out.),ping返回结果分析如下:

  • Pinging 192.168.124.88 with 128 bytes of data: 这说明正在ping 192.168.124.88,数据包大小为128 bytes
  • Request timed out. 这说明ping超时了都没有收到192.168.124.88主机的回应。
  • Ping statistics for 192.168.124.88: 说明这是ping 192.168.124.88的结果分析。
  • Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
    - Sent = 4,说明总共发送了4个数据包
    - Received = 0,说明所有发出去的数据包中收到回应的个数为0个
    - Lost = 4,说明发送的数据包中有4个包丢失了(即没有收到回应)
    - 100% loss 说明所有发送的数据包中100%的数据包都丢失了

正常能ping通的效果图如下:

这里可以看到,ping百度的域名,它解析到百度的ip为220.181.38.148,非常的快,发送128 bytes只需要37ms即可收到响应。返回结果分析如下:

  • Pinging baidu.com[220.181.38.148] with 128 bytes of data: 这说明正在ping baidu.com[220.181.38.148] ,数据包大小为128 bytes
  • Reply from 220.181.38.148: bytes=128 time=37ms TTL=50
    - Reply from 220.181.38.148: 这说明发送到220.181.38.148的数据包收到回应了
    - bytes=128,说明发送的数据包大小为128 bytes
    - time=37ms,说明数据包从发送出去到接收到回应,花了37毫秒时间。网络好不好就看这个时间了,像37毫秒就是网络非常好的了,在公司测试发现100毫秒上下也是OK的,数字越小越好,具体数字多大就会卡呢,自己试罢,反正如果你发现卡的时候,就看看这个数字是多少,慢慢的你就知道什么数字是好的,什么数字是差的了。
    - TTL=50,TTL(Time To Live,生存周期):每经过一次路由该值自减1,直至减到0时该IP包会被丢弃。通过这样的设置可以在路由遇到死循环时,避免IP包在环内不停转发,但不能达到目的地。
  • Approximate round trip times in milli-seconds: 往返行程的估计时间
  • Minimum = 37ms, Maximum = 38ms, Average = 37ms
    - 最短 = 37ms,即使用时间最短的那个数据包发送接收的使用时间
    - 最长 = 38ms,即使用时间最长的那个数据包发送接收的使用时间
    - 平均 = 37ms,即所有的数据包平均的发送和接收的使用时间

因为默认只ping四次,所以如果需要一直ping的话可以通过加 -t 参数,示例如下:

这时它就会一直ping,直到我们按Ctrl + C才会停止。

关于TTL,一般用默认值就行,为了方便理解,我们修改一下这个参数,使用 -i 可以修改,比如改成5次,然后ping baidu,看经过5次路由能否达到百度,如下:

啊哈,竟然会超时出现,我网络好的很,哎,也不追究这个为什么会出现超时了,反正网上是这么说的:TTL数值每经过一次路由就会减1,如果到0时还没有达到目标主机,就会返回失败了,返回的内容的就是上面的“Reply from 219.158.8.85: TTL expired in transit.”,中文含义为“来自 219.158.8.85的回复:TTL在传输过程中过期了。”

Android中的ping命令

在命令行中进入shell:

adb shell

执行效果如下:

这时,我们就可以输入ping命令执行了,如下:

和windows不同,windows默认只ping4次,而linux默认会不停地ping,直到我们按下Ctrl + C才停止。

在我的Android项目需求中,不能一直ping,只需要ping一段时间即可,通过 -c 命令可以指定ping的次数,比如设置成只ping4次,如下:

如上图,可以看到,Linux的ping返回结果和Windows的差不多,相同的我就不重复解释了,只说不同点,如下:

  • PING baidu.com (220.181.38.148) 56(84) bytes of data. 这里的56(84),56指的是数据包的大小为56bytes,84是什么我就不知道了,似乎括号里的这个数值和不带括号的总是相差28。下面一行我们看到有64 bytes,和56 bytes相差8。
  • icmp_seq=1 ping序列,从1开始,干嘛用的?我也不知道,在ping的时候你可以通过这个值了解到这是发送的第几个数据包了。
  • 4 packets transmitted, 4 received, 0% packet loss, time 3011ms
    - 4 packets transmitted,说明传输了4个包
    - time 3011ms 这是个什么时间?我也不知道,懒的去查了,开始我以为是整个ping过程所花的总时间,后来打开计时器看发现并不是。
  • rtt min/avg/max/mdev = 40.851/53.571/58.797/7.373 ms,rtt是舍意思?我也不知道,懒得查了,后面的,min是最短,avg是平均,max是最长,mdev?,我也不知道,懒得查。这里的最短、平均、最长和Widnows的是一样的含义,不多解释了。

在网络不好时,会发现ping命令一直没有输出内容,如下:

于是就想说,设置个超时时间吧,通过-W可以设置超时时间,这里我设置了超时为1000,我不知道这个1000是个什么单位,是毫秒啊,还是秒?测试发现在我网络不通的时候一直不结束,有可能这个单位是秒,所以超时时间就很长,那我就当它单位是秒吧,设置为10再试一下,发现还是没结果,如下:

那我设置ping的次数为4次,再试一下,如下:

我使用计时器看了一下,大概13秒结束返回结果,搞不懂这个-W设置的超时是个什么原理,跟Windows不一样啊,Windows是每发送一个数据包,如果超时了就会打印一行Request timed out,按照这个逻辑的话上面应该打印4行Request timed out,而且总时间应该是40秒,因为超时是10秒,ping 4次,如果4次都超时则为40秒,这才是正常行为,但是不知道为什么Android上这么奇怪,是因为Android修改过这个Linux底层了吗?带着这个疑问,我打开了我华为云上的Linux主机,发现效果是一样的,如下:

这说明Linux的超时设置就是有问题的!完全没有Windows的那个效果。这里有一篇文章在说为什么Linux ping超时了没有回显消息:https://blog.csdn.net/wj31932/article/details/111315405,文章大长了,我也懒得去慢慢看,这个超时参数不管用那我只能不用它了。

那在做Android开发时,如果网络不好ping命令一直不返回也不行啊,怎么结束ping操作啊?,我发现把ping的那个线程中断也不管用。

只输入ping就按回车,可以看到ping命令的所有参数,如下:

如上图,有一个参数为:-w deadline,注,这是小写的w,deadline中文含义为“最后期限”,其作用就是设置整个ping过程的时间,这个功能非常符合我的项目需求,我就是想要设置ping多久,比如我想设置ping30秒,我不管你30秒ping了多少次,我也不管你超时时间是多少,我也不管你网络好不好,反正30秒之后你一定要给我结束,使用如下:

我开计时器了,确实是30秒之后就结束了。

总结

ping命令的参数很多,但是真正在用的时候需要的参数也就一两个,所以掌握这一两个就够了。Windows中的ping用-l和-t参数就够了,Linux中的ping用-s和-w就够了,超时时间一般是不用设置的,用默认的就好了。

  1. Windows ping简单使用:ping -l 128 -t baidu.com
    - l 设置数据包大小为128 bytes
    - t 设置一直不停地ping
    - 示例如下:

  2. Linux ping简单使用:ping -s 120 -w 20 baidu.com
    - s 设置数据包大小为120 bytes,实际发送数据包时是128bytes,据说是会包含一些头信息什么的需要额外的8bytes,据我的实验,在Android手机中,默认是1秒ping一次,包含超时时间在里面,比如ping 20秒,不管网络好与不好,20秒后,看统计信息会显示发送的刚好是20个包。
    - w设置总的ping时间为20秒
    - 示例如下:

  3. 查看ping参数说明

    • Windows直接输入ping即可,如下:
    • Linux也是直接输入ping,如下:

      如果是在Linux电脑(在Android系统上不行),还可以使用man ping查看ping命令的详细使用手册,如下:


      这个手册非常详细,从这里可以看到-w和-W的单位为秒,百度里找到的文章大多数说是毫秒,真是一个个都是转载别人的,一个错个个错,所以,尽量找官网文档看,比较准确。

Android中使用代码完成Ping功能

重点:Android使用此函数来执行ping命令:Runtime.getRuntime().exec(“ping -s 56 -w 30 192.168.1.8”),这个函数执行之后会返回一个Process进程对象,通过读取这个进程的两个输入流即可获取到ping的结果,需要注意的是,系统是有可能交替往这两个流里面写入数据的,所以我们需要开两个线程同时读取这两个流(百度的文章里全是一个线程进行读取的),这里使用到了线程的合并功能(join()函数),通过join()函数可以实现让两个线程先执行完,所以这个示例中完美的展示了join()函数的使用,大家可以深刻体会到该函数的作用是怎样的,准确的说,join()函数并不是线程合并函数,而是一个等待函数,比如在A线程里调用了B线程的join()函数,则A线程就等着不动了,等到B线程执行结束了A线程才继续接着往下执行。

先上一个效果图:

这里设置ping的ip为百度的ip,ping 5秒钟,数据包大小为64字节,点击Start Ping按钮,效果如下:

代码如下:
1、首先开启ViewBinding功能,在build.gradle中配置,如下:

android {compileSdkVersion 30buildToolsVersion "30.0.3"buildFeatures {viewBinding true}
}

2、界面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:tools="http://schemas.android.com/tools"android:orientation="vertical"android:paddingTop="16dp"android:paddingBottom="16dp"tools:context=".MainActivity"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginLeft="16dp"android:layout_marginRight="16dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="16dp"android:text="Ping IP: "tools:ignore="SpUsage" /><EditTextandroid:id="@+id/etIp"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="16dp"android:inputType="phone"android:text="39.156.69.79"tools:ignore="Autofill,SpUsage" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginLeft="16dp"android:layout_marginRight="16dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="16dp"android:text="Ping多久(单位为秒): "tools:ignore="SpUsage" /><EditTextandroid:id="@+id/etTime"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="16dp"android:inputType="number"android:text="5"tools:ignore="Autofill,SpUsage" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginLeft="16dp"android:layout_marginRight="16dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="16dp"android:text="数据包大小(单位为字节): "tools:ignore="SpUsage" /><EditTextandroid:id="@+id/etSize"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="16dp"android:inputType="number"android:text="64"tools:ignore="Autofill,SpUsage" /></LinearLayout><Buttonandroid:gravity="center"android:id="@+id/btnStartPing"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Start Ping"android:textAllCaps="false"android:textColor="@android:color/white"android:textSize="16dp"android:layout_marginLeft="16dp"android:layout_marginRight="16dp"tools:ignore="SpUsage" /></LinearLayout>

3、代码:

class MainActivity : AppCompatActivity() {private lateinit var binding: ActivityMainBindingprivate lateinit var mAdapter: MyAdapterprivate val lines = ArrayList<String>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)mAdapter = MyAdapter()binding.recyclerView.layoutManager = LinearLayoutManager(this)binding.recyclerView.adapter = mAdapterbinding.btnStartPing.setOnClickListener {thread { ping() }}}private fun ping() {val ip = binding.etIp.text.trim().toString()val sizeStr = binding.etSize.text.trim().toString()val time = binding.etTime.text.trim().toString()if (ip.isBlank()) {runOnUiThread { Toast.makeText(this, "请输入IP", Toast.LENGTH_SHORT).show() }return}if (sizeStr.isBlank()) {runOnUiThread { Toast.makeText(this, "请输入数据包大小", Toast.LENGTH_SHORT).show() }return}if (time.isBlank()) {runOnUiThread { Toast.makeText(this, "请输入要ping多久", Toast.LENGTH_SHORT).show() }return}if (!isValidIpAddress(ip)) {runOnUiThread {AlertDialog.Builder(this).setTitle("提示").setMessage("您输入的IP地址格式有误,请修正!").show()}return}runOnUiThread {binding.btnStartPing.isEnabled = falselines.clear()addData("Ping开始")}val size = sizeStr.toInt() - 8val command = "ping -s $size -w $time $ip"// 注:正常ping数据和错误ping数据可能会交替输出,所以需要开两个线程同时读取val process = Runtime.getRuntime().exec(command)val inputStreamThread = readData(process.inputStream) // 读取正常ping数据val errorStreamThread = readData(process.errorStream) // 读取错误ping数据// 等待两个读取线程结束inputStreamThread.join()errorStreamThread.join()runOnUiThread {addData("Ping结束")binding.btnStartPing.isEnabled = true}}private fun readData(inputStream: InputStream?) = thread {try {BufferedReader(InputStreamReader(inputStream)).use { reader ->var line: String?while (reader.readLine().also { line = it } != null) {val lineTemp = line!!runOnUiThread { addData(lineTemp) } // 这里切换到了UI线程,子线程继续执行时可以已经把line对象又赋值为null了,所以使用了lineTemp来预防值被重新赋值}}} catch (e: Exception) {runOnUiThread { addData("出现异常:${e.javaClass.simpleName}: ${e.message}") }}}private fun addData(data: String) {lines.add(data)refreshListView()}private fun refreshListView() {mAdapter.notifyDataSetChanged()binding.recyclerView.scrollToPosition(lines.size - 1)}/*** 验证给定的ip地址是否有效* @param ip*/private fun isValidIpAddress(ip: String?): Boolean {if (ip.isNullOrBlank()) return falseval regex = "(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})(\\.(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})){3}"val pattern = Pattern.compile(regex)val matcher = pattern.matcher(ip)return matcher.matches()}internal inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {var textView: TextView = itemView.findViewById(android.R.id.text1) as TextView}internal inner class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {return MyViewHolder(View.inflate(parent.context, android.R.layout.simple_list_item_1,null))}override fun onBindViewHolder(holder: MyViewHolder, position: Int) {holder.textView.text = lines[position]}override fun getItemCount(): Int {return lines.size}}
}

也可从码云中下载完整代码:https://gitee.com/daizhufei/android-ping

android中的ping命令使用相关推荐

  1. android音视频工程师,音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源)...

    ## 音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源) ## 视音频编辑器 ## 前言 有时候我们想对音视频进行加工处理,比如视频编辑.添加字幕.裁剪等功能处 ...

  2. Android系统篇之—-Android中的run-as命令引出升降权限的安全问题(Linux中的setuid和setgid)

    一.前言 最近一周比较忙,没时间写东西了,今天继续开始我们今天的话题:run-as命令,在上周的开发中,遇到一个问题,就是在使用run-as命令的时候出现了一个错误,不过当时因为工作进度的问题,这问题 ...

  3. Android中的su命令使用

    Android开发工具系列目录 Android项目中Git工具的使用 史上最全Git命令使用手冊 史上最新最全的ADB命令行 Android中的su命令使用 Postman测试WebService接口 ...

  4. Android中的run-as命令引出升降权限的安全问题

    转载自:http://blog.csdn.net/jiangwei0910410003/article/details/51405631 一.前言 最近一周比较忙,没时间写东西了,今天继续开始我们今天 ...

  5. Android系统篇之----Android中的run-as命令引出升降权限的安全问题 Linux中的setuid和se

    一.前言 最近一周比较忙,没时间写东西了,今天继续开始我们今天的话题:run-as命令,在上周的开发中,遇到一个问题,就是在使用run-as命令的时候出现了一个错误,不过当时因为工作进度的问题,这问题 ...

  6. linux中ping命令详解,linux中的ping命令的详细解释

    linxu下的ping命令的主要功能就是确定网络状态,下面由秋天网 Qiutian.ZqNF.Com小编为大家整理了linux的ping命令的详细解释的相关知识,希望对大家有帮助! 一.linux中的 ...

  7. Android录屏并利用FFmpeg转换成gif(三) 在Android中使用ffmpeg命令

    Android录屏并利用FFmpeg转换成gif(三) 写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲这种方 ...

  8. 安卓java代码ping网关_Android代码中使用Ping命令

    项目中需要搜索同一WIFI局域网中的设备并进行通信,暂时想到的办法是得到局域网网段的地址,因为同一局域网中的IP地址前三位是相同的,而第四位的范围从0~250,所以对第四位进行遍历搜索,能ping通的 ...

  9. Android中的ping网络实现

    android中判断是否联网的那个方法在某些情况下是不可靠的,其实最可靠的就是ping当前的网络例如ping百度看下能不能ping通,能就代表网络正常,不能就表示网络不正常,以下就是ping的代码实现 ...

最新文章

  1. 一起学nRF51xx 23 -  s130蓝牙API介绍
  2. test_bit、set_bit和clear_bit
  3. c++命令模式command
  4. Python爬虫自学之第(①)篇——爬虫伪装和反“反爬”
  5. 搜索表单制作语法:强大的搜索功能
  6. 对比图像分类五大方法:KNN、SVM、BPNN、CNN和迁移学习
  7. python3字节转化字符_浅谈 Python3 中对二进制数据 XOR 编码的正确姿势
  8. oracle,sqlserver,mysql区别
  9. PL/SQL 实现行列转换
  10. SQL50题面试题(10-15)
  11. DialogPlus
  12. Python核心编程总结(一、基础概念与语法)
  13. 联想服务器TS540装系统蓝屏,联想装win7蓝屏0x000000a5超详细图文解决方案
  14. choco 代理强制失效方法
  15. java有一只兔子 从出生_Java解决题目:有一对兔子,从出生第三个月起每个月都生一对兔子,小兔子长到第三个月后,每个月又生一对兔子。。。...
  16. wp兼容了android应用程序,WP比安卓流畅 但为什么就不好用呢?
  17. 免费PDF批量转换图片工具
  18. 自动焊锡机加锡时的注意事项
  19. 2018.10.04 codeforces1060E. Sergey and Subway(树形dp)
  20. 长处比短板更容易困住你,读《能力陷阱》有感

热门文章

  1. 各地级市GDP及第一二三产业GDP数据(1999-2019年)
  2. win7计算机电源设置在哪里设置,windows7电源管理设置在哪里_win7的电源管理在哪里打开-win7之家...
  3. java吉祥物_编程语言的吉祥物
  4. Bilibili 移动端组件化实践中的冷启动优化
  5. 解决前后端分离中文件传输跨域失败问题
  6. JavaStudy5(坦克大战)—B站韩顺平
  7. Element 表格固定列横向滚动条无法拖动的问题解决
  8. 李宏毅《机器学习》飞桨特训营(二)——回归(含作业:PM2.5预测)
  9. 赫卡忒的眼眸:微光手机“夜视仪”是怎样炼成的?
  10. 有好用的防水蓝牙耳机吗?蓝牙防水耳机排行榜