Scala的简单学习一

news2025/3/17 3:49:07

一 相关知识

1.1 scala的安装

1.在idea中导入依赖,并在Idea下载scala插件

1.2 scala基础知识点

1.scala代码中一行语句的结束是以换行符为标准,可以不用写分号

2.class是一个普通的类,object相当于一个单例对象,object类中的方法相当于加上一个static关键字

二 基础知识

2.1 基本数据类型

Byte、Short、Int、Long、Float、Double、Char、Boolean

2.2 定义变量常量

var 变量名:数据类型=数值

val 变量名:数据类型=数值

注意:定义了变量后续使用不需要指明类型

package com.shujia.day01

object Demo1 {
  def main(args: Array[String]): Unit = {
    println("hello world")
    var a: Int = 10
    val b: Int = 19
    var c: String = "hello"
    println(a)
    println(b)
  }

}

2.3 获取数据类型

变量名.getClass  或者 变量名.getClass.getSimpleName方法查看数据类型

package com.shujia.day01

object Demo1 {
  def main(args: Array[String]): Unit = {
    println("hello world")
    var a: Int = 10
    val b: Int = 19
    var c: String = "hello"
    println(a)
    println(b)
    println(a.getClass.getSimpleName) //int
    println(c.getClass)//class java.lang.String
  }

}

2.4 字符串拼接

1.scala提供了一个方法类似拼接的方式语法 s"${xx}"

package com.shujia.day01

object Demo1 {
  def main(args: Array[String]): Unit = {
    println("hello world")
    var a: Int = 10
    val b: Int = 19
    var c: String = "hello"
    println(a)
    println(b)
    println(a.getClass.getSimpleName) //int
    println(c.getClass)//class java.lang.String

    var str:String=s"${a}|${b}"
    println(str)//10|19

  }

}

2.数组里面有个方法可以将数组里面的元素拼接

数组.mkString(拼接符号)

2.5 控制语句

2.5.1 选择语句

if else语句

package com.shujia.day01

import java.util.Scanner

object Demo2 {
  def main(args: Array[String]): Unit = {
    val sc: Scanner = new Scanner(System.in)
    println("请输入您的年龄")
    val age: Int = sc.nextInt()
    if(age<18){
      println("未成年")
    }else{
      println("成年")
    }

  }

}

while 循环

注意 :scala里面不支持++与--的

package com.shujia.day01

import java.util.Scanner

object Demo2 {
  def main(args: Array[String]): Unit = {
    val sc: Scanner = new Scanner(System.in)
    println("请输入您的年龄")
    val age: Int = sc.nextInt()
    if(age<18){
      println("未成年")
    }else{
      println("成年")
    }
    val array1: Array[Int] = Array(11, 22, 33, 44, 55)
    var i: Int = 0
    while (i<array1.length){
      println(array1(i))
      i += 1
    }

  }

}

2.5.2 循环语句

1.注意Scala里面没有for循环,他只适用于遍历各个容器

2.容器for循环

   val array1: Array[Int] = Array(11, 22, 33, 44, 55)
    var i: Int = 0
    while (i<array1.length){
      println(array1(i))
      i += 1
    }

    for (elem <- array1) {
      println(elem)

    }

3.不是容器的for循环

to:表示可以取到右边的

util:表示取不到右边的

 for (e <- 1 to 10){
      println("hello world")
    }

    for (e <- 1 until  10){
      println("hello world")
    }

2.5.3 控制条件

1.Scala里面的break countie 是没有的需要导包 

import scala.util.control.Breaks._    // _相当于java中的*

2.Scala里面break 需要抛出异常

  breakable{
      for (e <- 1 until  10){
        if (e==5){
          break
        }
        println(e)
      }
    }

2.6 IO流

2.6.1 读文件

1.Scala里面有一个 Source类 读取文件

2.Source的对象的getLines获取的是迭代器对象

package com.shujia.day01

import scala.io.{BufferedSource, Source}

object Demo3IO {
  def main(args: Array[String]): Unit = {
    //获取文件对象
    val bs: BufferedSource = Source.fromFile("scala/data/demo")
    //创建读文件的迭代器
    val lines: Iterator[String] = bs.getLines()
    for (elem <- lines) {
      println(elem)
    }
  }


}

2.6.2 写文件

1.Scala里面木单独的类写文件,只能依靠Java里面的方法

val bw = new BufferedWriter(new FileWriter("scala/data/out1.txt"))
    bw.write("hello world1")
    bw.newLine()
    bw.write("hello world2")
    bw.close()

2.7 函数

2.7.1函数的定义

1.定义在object里面的叫函数,定义在class里面的叫方法

2.主函数

* def: 定义函数或者方法的关键字

* main: 函数名 main函数是被java虚拟机所特有识别的程序入口

* args: 参数名

* Array[String]: 参数的数据类型

* Unit: 返回值类型 相当于java中的void

3.函数可以在object任意一个位置定义

2.7.2 函数的调用

在object对象内部,函数相当于加了一个static,将来调用的时候,可以使用object对象名进行调用

在同一作用域中,调用时可以不加对象名

package com.shujia.day02

object Demo4Func {
  def main(args: Array[String]): Unit = {
    /** def: 定义函数或者方法的关键字
    * main: 函数名 main函数是被java虚拟机所特有识别的程序入口
    * args: 参数名
    * Array[String]: 参数的数据类型
    * Unit: 返回值类型 相当于java中的void
    */
    println(add(2,4))
    println(Demo4Func.add(2,4))



  }
  //定义一个add函数
  def add(a:Int,b:Int):Int={
    return a+b
  }
}

2.7.3 函数的简写

1、如果函数体中最后一行语句作为返回值的时候,return可以省略不写

2、如果函数体中只有一行语句实现,那么大括号也可以不用编写

3、函数的返回值可以进行自动类型推断,可以省略不写

4、如果函数没有参数列表的话,()也可以省略不写,def add5 = println("好好学习,天天向上")

  //函数最后一句是返回的话,return可以不写
  def add1(x: Int, y: Int): Int = {
    x + y
  }
  //如果函数体中只有一行语句实现,那么大括号也可以不用编写
  def add2(x:Int,y:Int):Int=x+y
  //函数的返回值可以进行自动类型推断,可以省略不写
  def add3(x:Int,y:Int)=x+y
  //如果函数没有参数列表的话,()也可以省略不写
  def add4=println("hello")

5.如果函数只有一个参数,那么调用的时候可以简写

直接所属object 方法名 参数

  def add6(x: Int): Int = {
    x+200
  }
println(Demo4Func add6 3)

2.7.4 函数的递归

 def jieCheng(i: Int): Int = {
    if (i == 1) {
      1
    } else {
      i * jieCheng(i - 1)
    }
  }

2.6 异常

1.scala默认处理异常的方式是向外抛,如果出错,后续代码不会执行

2.scala处理异常的另一种方式和java一样,也是try..catch..但是和java的写法不太一样

package com.shujia.day02

import java.io.FileNotFoundException

object Demo5Exception {
  def main(args: Array[String]): Unit = {
    try {
      //      val br = new BufferedReader(new FileReader("scala/data/sssss")) // FileNotFoundException
      //      val array1: Array[Int] = Array(11, 22, 33) // ArrayIndexOutOfBoundsException
      //      println(array1(4))
      Class.forName("com.shujia.Demo")

    } catch {
      //模式匹配
      case e:FileNotFoundException => println("文件找不到异常")
      case e:ArrayIndexOutOfBoundsException => println("数组索引越界异常")
      //      case e:Exception => e.printStackTrace()
      case _ => println("其他异常")
    }finally {
      //无论有没有对应的case捕获,都会执行
      println("finally")
    }


    println("over")
  }

}

3.其中的匹配模式在后面会说到

三 进阶知识

3.1 类与对象

3.1.1相关知识

1.有一个共同的父类 object

2.使用单例对象

3.1.2 构造方法

1.在new对象的时候,构造方法必须手动创造,并重载,并放在开头写



class Student {
  println("好好学习天天向上")

  def this(x:Int,y:Int) {
    this()
    println(x+y)
  }

}

object Demo6Object {
  def main(args: Array[String]): Unit = {
    val student = new Student(10,20)
  }

}
//好好学习天天向上
30

3.1.3 成员变量

1.创建成员变量默认语法

 var _变量名:类型=_

2._表示占位符,将来可以传值进去

package com.shujia.day02

class Student2 {
  //定义成员变量
  private var _name: String = _
  private var _age: Int = _
  //构造方法
  def this(name:String,age:Int) {
    this()
    this._name=name
    this._age=age
  }


  override def toString = s"姓名${_name},年龄${_age}"
}

3. 私有成员变量

不提供get set方法 需要我们自己写

set有参数无返回值,get无参数有返回值

package com.shujia.day02

class Student2 {
  //定义成员变量
  private var _name: String = _
  private var _age: Int = _
  //构造方法
  def this(name:String,age:Int) {
    this()
    this._name=name
    this._age=age
  }
  //只有一条语句大括号可以省略
  def setName(name:String):Unit =this._name
  //没有参数 小括号可以不用写
  def getName:String=this._name

  def setAge(age:Int):Unit=this._age

  def getAge: Int =this._age


  override def toString = s"姓名${_name},年龄${_age}"
}

4.创建类的时候 传参

package com.shujia.day02

class Student3 (name:String,age:Int){
  //定义成员变量
  private var _name: String = name
  private var _age: Int = age
  private var _ad:String=_

  def this(name:String,age:Int,ad:String) {
    this(name,age)
    this._ad=ad
  }

  override def toString = s"姓名${_name},年龄${_age},地址${_ad}"

}

这个在new对象的时候可以传2个值页可以传三个值,如果是两个值,定义class时没有传入的默认是null值,

 3.1.4 成员方法

太简单 不说了

3.2 继承

跟java差不多,无需多言

3.3 伴生对象

1.object与class 创建的类的名字相同,class创建的类叫伴生对象

2.object创建的对象无法new出来。但是可以通过apply方法创建对象

package com.shujia.day02

object Demo7Apply {
  def main(args: Array[String]): Unit = {
    val phone2 = new Phone2("华为", 8000)
    println(phone2)
    val phone1: Phone2 = Phone.apply("苹果", 10000)
    println(phone1)
  }
}

object Phone {
  def apply(kind: String, price: Int): Phone2 = new Phone2(kind, price)
}


class Phone2(kind: String, price: Int) {

  override def toString = s"品牌:${kind}, 价格:${price}"
}

3.4 样例类

1.与普通的类的区别:

普通的类需要重写toString方法才能获取值,要不然打印的是地址值

默认不能修改值,需要修改,将case定义类的时候用var

2.在case定义类的时候可以暂时给定一个默认值用var修饰,后面创建对象的时候可以改

package com.shujia.day02

object Demo8Cass {
  def main(args: Array[String]): Unit = {
    val u1 = new User("慌", 19)
    println(u1)//com.shujia.day01.User@2a18f23c
    u1.ad="安全"
    println(u1)
  }
}


//class User(name:String,age:Int)


case class User(var str: String, i: Int,var ad:String="合肥");

四 面向函数式编程

4.1 函数作为参数

4.1.1 基础知识

1.将函数看作对象

2.使用 =>确定类型

4.1.2 函数作为值复制给变量

package com.shujia.day02

object Demo9Func {
  def main(args: Array[String]): Unit = {

    //创建一个函数将字符串变成int类型
    def strToInt(str:String):Int={
      str.toInt
    }

    val i1: Int = strToInt("1000")
    println(i1)//1000

    //定义一个变量接收这个函数,刚刚好这个变量的类型也是字符串变成int类型
    val strToIntTemp : String=>Int =strToInt
    val i2: Int = strToIntTemp("2000")
    println(i2)//2000

  }





}

4.1.3 参数是函数的函数

1.传入的是参数是啥类型的函数,啥类型是你目标参数需要的

 //定义一个参数是函数的函数

    /**
     * 定义了一个fun函数,函数的参数是一个参数为String类型返回值是Int类型的函数
     */
    def fun(f:String=>Int):Unit={
      val i3: Int = f("3000")
      println("这是fun函数")
      println(i3)
    }

    //定义一个参数是String类型的,返回值是Int类型的函数
    def method1(str:String):Int={
      println("这是method1函数")
      str.toInt+1000
    }

    //调用fun函数
    fun(method1)

4.1.4 使用匿名函数改写

没有名字的函数

语法:

(参数列表)=> 返回值类型

1.匿名函数可以用一个变量接收,然后再传入主体函数中

2.匿名函数的返回值类型可以自动判断,不需要标明,标明就错了

3.当主体函数只有一句话的时候,可以直接传入匿名函数

4.匿名函数的参数类型也可以不写,但是会有警告,最好写上

5.当匿名函数中传入的参数只用了一次,且主体函数只有一句话的时候,可以用下划线代替匿名函数的参数 

    //创建匿名函数
    //val f1: String => Int  定义了一个变量是类型是String转化成Int类型
    //(s: String) => s.toInt   创建了一个匿名函数,这函数的作用就是将String变成Int
    //(s: String) => s.toInt  这里的匿名函数也是简写的,因为函数的主体只有一句话,可以省区大括号,如果还想添加其他的,要加上大括号
    //(s: String) => s.toInt 在匿名函数中 返回值的类型不需要写,会自动判断的
//    val f1: String => Int = (s: String):Int => {s.toInt}//这样会报错
    val f1: String => Int = (s: String) => {s.toInt}

    //调用fun函数
    fun("80",f1)

    //当函数只有一行的时候,可以直接传入匿名函数
    fun("88",(s:String)=>{s.toInt})

    //lambda表达式的参数类型可以进行自动推断,不推荐这样,因为会有警告,最好加入匿名函数的参数类型
    fun("22", s => s.toInt)

    //如果传入的函数参数有且仅只用了一次的话,可以直接使用_代替
    fun("22", _.toInt)

4.1.5 实例

package com.shujia.day02

object Demo10Func {
  def main(args: Array[String]): Unit = {
    //定义一个数组
    val array: Array[Int] = Array(11, 22, 33, 44, 55, 66, 77, 88, 99)

    //1 之前的for遍历数组
    for (elem <- array) {
      println(elem)
    }
    println("="*100)

    //使用foreach函数遍历
    //f: A => U ,参数是有类型的,返回值无类型的
    array.foreach(f)
    //定义一个函数f,参数是有类型的,返回值无类型的
    def f(i:Int): Unit ={
      println(i)
    }

    println("="*100)
    //使用匿名函数
    array.foreach((i:Int)=>{println(i)})
    //参数类型不写
//    array.foreach(i=>{println(i)})//会有警告,最好加上类型
    //用_代替参数
    array.foreach(println(_))

    //使用Scala自动any类中的方法
    //以后遍历数组就这样写
    array.foreach(println)


  }

}

4.2 函数作为返回值

4.2.1 参数与返回值都是函数

1.调用函数得到也是一个函数

//定义一个参数类型是String->Int的函数,返回值是一个参数列表为String->Int类型的函数
    def fun(f:String=>Int):String=>Int={
      println("好好学习天天向上")
      f
    }
    //使用匿名函数调用了fun函数,因为fun函数有返回值,所以用一个变量接收,刚刚好这个变量又是函数,可以调用
    val show: String => Int = fun((s: String) => s.toInt)
    //调用show函数
    println(show("1000"))

4.2.2 只有返回值是函数

1.返回值是啥类型,就要在内部创建一个改样类型的函数。

2.返回值直接写内部创建函数的函数名

3.调用函数得到也是一个函数

4.对于这种的可以直接简化

5.好处:传值可以分开,当函数原本一次性传递多个参数的时候,现在改成分开传递参数的形式,增加了函数的灵活性和可复用性,scala的函数柯里化:函数的返回值依旧是一个函数,继续传参

   //定义一个参数类型为String,返回值是参数列表是String->Int的函数
    def fun1(str:String):String=>Int={
      //因为这里的返回值是参数列表是String->Int的函数,需要在fun1里面创建一个这样的函数
      def show1(s:String):Int={
        str.toInt+s.toInt
      }
      //需要返回一个参数列表是String->Int的函数
      show1
    }
     //上面函数的简写形式
    def fun2(str: String)(str1: String): Int = {
        str.toInt+str1.toInt
    }

    //调用fun2函数
    println(fun2("1000")("1000"))
    //调用fun1函数
    val get: String => Int = fun1("1000")//这是函数
    val i: Int = get("1000")
    println(i)
    //简化写法
    val i1: Int = fun1("1000")("1000")
    println(i1)

6.偏函数:中间由scala产生的函数,称之为偏函数

def fun3(str1:String,str2:String):Int={
      str1.toInt+str2.toInt
    }
    //偏函数
    val show3: String => Int = fun3("10", _)
    println(show3("10"))
    println(show3("20"))
    println(show3("30"))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1694795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git分支策略(github-flow VS git flow,如何选择)

一. 结论 Github flow&#xff1a;最简单 小型项目&#xff0c;持续部署&#xff0c;自动化测试程度高&#xff0c;发布流程简单 Git flow&#xff1a;复杂但最常用 大型项目&#xff0c;发布周期长&#xff0c;需要同时维护多个版本&#xff0c;发布流程复杂 表格提供了不…

36PE启动盘新秀:Ventoy(附各种PE的ISO下载)

PE启动盘新秀:Ventoy(附各种PE的ISO下载) 在我们以前的认知中,一个U盘只能制作包含一个系统的启动盘.比如,安装了微PE工具箱的U盘就不能安装其他什么PE工具箱了.这有时候让我们很无奈,只能买好多U盘,一个U盘一个PE系统. 这个问题的本质是什么?事实上,笔者认为,就是单个的ISO文…

Andoird使用Room实现持久化及使用Room进行增删查改

文章目录 Room概述Room的使用一、在gradle.build中添加依赖库kotlinJava 创建实体类创建抽象Dao层接口创建DataBase层使用创建的查看数据库 总结&#xff1a; 这篇文章会告诉你如何在Android中通过kotlin或者Java来实现数据持久化 Room概述 处理大量结构化数据的应用可极大地受…

2024年【N1叉车司机】考试题及N1叉车司机找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 N1叉车司机考试题参考答案及N1叉车司机考试试题解析是安全生产模拟考试一点通题库老师及N1叉车司机操作证已考过的学员汇总&#xff0c;相对有效帮助N1叉车司机找解析学员顺利通过考试。 1、【多选题】《特种设备使用…

FreeRTOS 源码概述

FreeRTOS 目录结构 使用 STM32CubeMX 创建的 FreeRTOS 工程中&#xff0c;FreeRTOS 相关的源码如下: 主要涉及2个目录&#xff1a; Core Inc 目录下的 FreeRTOSConfig.h 是配置文件 Src 目录下的 freertos.c 是 STM32CubeMX 创建的默认任务 Middlewares\Third_Party…

深入解析编程逻辑中的关键字与逻辑运算

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、认识关键字及其重要性 二、逻辑运算的关键字 1. and、or 和 not 的运用 2. 逻辑运算的…

42-3 应急响应之服务排查

一、服务排查 服务是后台运行的进程,可在计算机启动时自动启动,也可暂停和重新启动,且不显示用户界面。它们特别适用于长时间运行的功能,以避免影响其他用户在同一台计算机上的工作。在应急响应中,服务常被恶意软件用作驻留方法。 二、Windows服务排查 打开【运行】对话框…

【独家揭秘!玩转ChatGPT?一文带你解锁秘籍!】

&#x1f680;【独家揭秘&#xff01;玩转ChatGPT&#xff1f;一文带你解锁秘籍&#xff01;】&#x1f680; &#x1f449; 【直达ChatGPT体验站】 ChatGPT&#xff0c;全称“Chat Generative Pre-trained Transformer”&#xff0c;是人工智能研究实验室OpenAI于2022年底推出…

9.2 Go语言入门(包和导入)

Go语言入门&#xff08;包和导入&#xff09; 目录一、包和导入1. 包&#xff08;Package&#xff09;1.1 包的定义1.2 包的作用1.3 main 包1.4 非 main 包 2. 导入&#xff08;Import&#xff09;2.1 导入标准库2.2 导入第三方包2.3 导入本地包2.4 导入别名2.5 导入并调用初始…

第四课 communcation服务-can配置第二弹

Davinci配置目标: 介绍DBC基本属性,并且配置出一个DBC。 将DBC导入到vector的davinci工具,生成我们想要的代码。 Davinci配置步骤: 1. 编辑DBC文件 DBC文件是一种非常重要的工具,所谓DBC就是Database CAN,CAN网络的数据库文件,定义了CAN网络的节点、消息、信号的所有…

查看远程桌面连接登录不上服务器,远程桌面连接登录不上服务器是什么情况?怎么解决?

在信息技术领域&#xff0c;远程桌面连接&#xff08;RDP&#xff09;是一种重要的远程管理工具&#xff0c;它允许管理员或用户从远程位置访问和控制服务器或计算机。然而&#xff0c;在实际操作中&#xff0c;远程桌面连接不上服务器的情况时有发生&#xff0c;这通常是由多种…

Redis 完整

Redis 什么是 redis ? 是一种基于键值对的 NoSql 型数据库。与 hashMap 不同的是&#xff0c;Redis 中的 value 支持 string&#xff08;字符串&#xff09;、hash&#xff08;哈希&#xff09;、 list&#xff08;列表&#xff09;、set&#xff08;集合&#xff09;、zset…

Kafka(十三)监控与告警

目录 Kafka监控与告警1 解决方案1.2 基础知识JMX监控指标代理查看KafkaJMX远程端口 1.3 真实案例Kafka Exporter:PromethusPromethus Alert ManagerGrafana 1.3 实际操作部署监控和告警系统1.2.1 部署Kafka Exporter1.2.2 部署Prometheus1.2.3 部署AlertManger1.2.4 添加告警规…

3D透视图转的时候模型闪动怎么解决?---模大狮模型网

在3D建模与渲染的世界中&#xff0c;透视图是我们观察和操作模型的重要窗口。然而&#xff0c;有时候在旋转透视图时&#xff0c;模型会出现闪动的现象&#xff0c;这不仅影响了我们的工作效率&#xff0c;还可能对最终的渲染效果产生负面影响。本文将探讨这一问题的成因&#…

【Text2SQL 经典模型】HydraNet

论文&#xff1a;Hybrid Ranking Network for Text-to-SQL ⭐⭐⭐ arXiv:2008.04759 HydraNet 也是利用 PLM 来生成 question 和 table schema 的 representation 并用于生成 SQL&#xff0c;并在 SQLova 和 X-SQL 做了改进&#xff0c;提升了在 WikiSQL 上的表现。 一、Intro…

WGCAT工单系统如何配置通知

WGCAT工单系统可以配置邮件通知 只要配置了邮件通知&#xff0c;那么一旦我们账号有新的工单需要处理&#xff0c;就会接受到邮件通知 除了邮件之外&#xff0c;还可以配置其他方式的通知&#xff0c;比如微信钉钉短信等方式&#xff0c;参考如下 https://www.wgstart.com/wgc…

Docker常用软件安装

文章目录 1.安装Tomcat1.docker hub查找镜像并复制拉取镜像命令2.拉取镜像到本地1.执行官网命令2.查看是否拉取成功 3.启动tomcat4.退出和重启1.由于是以交互方式启动的&#xff0c;所以不方便&#xff0c;直接ctrl c退出2.查看当前的容器3.使用docker start 命令启动容器&…

内外网文件传输安全可控的方式有哪些?这几款软件值得参考

在信息化时代&#xff0c;随着企业对网络安全和数据保护需求的日益增强&#xff0c;内外网隔离已成为一种常见的网络安全策略。内外网隔离旨在防止未经授权的访问和数据泄露&#xff0c;确保企业网络的安全稳定。然而&#xff0c;在实施内外网隔离的同时&#xff0c;如何实现文…

读书笔记-Java并发编程的艺术-第1章 并发编程的挑战

文章目录 1.1 上下文切换1.1.1 多线程一定快吗1.1.2 如何减少上下文切换 1.2 死锁1.3 资源限制的挑战 1.1 上下文切换 即时是单核处理器也支持多线程执行代码&#xff0c;CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给多个线程的时间&#xff0c;因为时间…

H3CNE-6-ICMP数据包分析

ICMP&#xff1a;Internet Control Message Protocol ICMP用来传递差错、控制、查询等信息 Wireshark抓包 Wireshark下载国内镜像 ICMP数据包格式 Type&#xff1a;表示ICMP消息类型 Code&#xff1a;表示同一消息类型中的不同信息 ICMP消息类型和编码类型 ICMP应用 &…