2024年8月

前言

在物联网(IoT)和工业自动化领域,边缘计算设备扮演着至关重要的角色。边缘采集网关作为连接物理世界与数字世界的桥梁,负责收集传感器数据并将数据传输到云端或本地数据中心进行处理。

本文将介绍一款基于 .NET 8 的跨平台高性能边缘采集网关的开源项目。希望通过这个项目能够帮助大家搭建和部署高效的边缘采集解决方案。

项目介绍

基于.NET 8 的跨平台高性能边缘采集网关,单机采集数据点位可达百万。

ThingsGateway
是C#开发的一款边缘采集网关,核心分为四大部分。

  • 通道

通道,实际上相当于一个实际的通讯链路,比如一个串口,一个TCP连接等,在
ThingsGateway
中, 通道也会作为线程池中的一个任务,对于同一个通道中的不同设备,采集/业务方法是顺序进行的。

  • 插件

ThingsGateway中的采集方法或者上传方法等都由插件完成,主程序只负责调度执行。 对于不同的采集协议或者业务需求,可以通过开发插件完成自定义的业务操作。

  • 设备

建立设备,必须指定通道以及插件,也可以说设备其实是插件的配置。 同时对于采集设备、业务设备,会有些许差别。

采集设备:采集数据入网关/写入数据到现场

业务设备:上传数据到第三方/第三方RPC反写

  • 变量

变量,用于配置采集设备的具体点位详情,以及对应业务设备中的配置项

项目特点

  • 可视化操作

通过web浏览器配置,调试,验证整个流程

  • 脚本支持

灵活的数据转换脚本以及数据上传自定义实体脚本,可适配各大云平台的物模型

  • 自定义插件支持

通过开发插件完成自定义的业务操作。

  • 性能

测试100w变量点位,500ms-1000ms全部采集完成,稳定连续采集占用CPU资源、内存资源低。

  • 断线缓存

支持断线缓存,恢复后自动上传。

  • 完整可商用的边缘网关

完善的配置权限,操作日志功能等,还有OPC、WebAPI、Mqtt、Kafka、时序库、变量报警等更多功能等待你发现。

项目插件

  • 采集插件
插件名称 备注
Modbus Rtu/Tcp报文格式,支持串口/Tcp/Udp链路
SiemensS7 西门子PLC S7系列
Dlt6452007 支持串口/Tcp/Udp链路
OpcDaMaster 64位编译
OpcUaMaster 支持证书登录,扩展对象,Json读写
  • 业务插件
插件名称 备注
ModbusSlave Rtu/Tcp报文格式,支持串口/Tcp/Udp链路,支持Rpc反写
OpcUaServer OpcUa服务端,支持Rpc反写
MqttClient Mqtt客户端,支持Rpc反写,脚本自定义上传内容
MqttServer Mqtt服务端,支持WebSocket,支持Rpc反写,脚本自定义上传内容
KafkaProducer 脚本自定义上传内容
RabbitMQProducer 脚本自定义上传内容
SqlDB 关系数据库存储,支持历史存储和实时数据更新
SqlHisAlarm 报警历史数据关系数据库存储
TDengineDB 时序数据库存储
QuestDB 时序数据库存储

项目展示

1、ThingsGateway 演示地址

账户 : SuperAdmin

密码 : 111111

2、登录页面

3、系统首页

4、网关管理

5、网关状态

6、网关日志

项目地址

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号
[DotNet技术匠]
社区,与其他热爱技术的同行一起交流心得,共同成长!

本文上回书接《
这是DDD建模最难的部分(其实很简单)
》,欢迎关注我的同名公众号,获取框架源码。
https://mp.weixin.qq.com/s/HZKMLF0_I10iczzp2mAR-w

故事背景

2013年中,我们的Java后端团队为了落地DDD,全面引入了dotnet技术栈,具体过程和成果,可以看我的B站频道《Java8 到 .NET8,团队升级报告 - 第二弹》
https://www.bilibili.com/video/BV14YgYedE1f
在近半年的时间,我将自己落地DDD的实践经验进行提炼和总结,以公众号文章和B站视频的方式分享出来,与更多的网友建立链接和交流,得到了很多肯定反馈,也因为大家提供的视角,使得我自己对DDD的认知有了更深层次的迭代。
目前我们借助dotnet强大的生态以及csharp优良的语言设计,已经可以非常丝滑地用代码表达模型和业务,整个软件交付的体验和效率,获得了前所未有的进步。我们netcorepal-cloud-framework框架在这个过程中也得到了进化和可用性验证,我们坚信找到了一套更加务实的软件设计认知和方法论。

Javaer太难了

由于我们团队实际上还是Java和csharp双技术栈,于是我们萌生了一个想法,是否可以让我们的Java项目交付过程也如此地丝滑?带着这个想法,我们开始在Java生态中寻找可以帮助我们构建出类似csharp框架效果的组件:
  • Web框架: aspnetcore vs springboot
  • ORM:EntityFrameworkCore vs JPA
  • 中介者模式:MediatR vs ?
  • 事件的最终一致性实现:CAP vs ?
其中“中介者模式”和“事件的最终一致性”实现我们没有找到合适的替代品,经过分析,“中介者模式”并不是必须的,虽然最终实现起来,没有csharp那么优雅,但并不影响对建模设计的实现,但“事件的最终一致性”这个组件,我们认为是必不可少的,我们建模最底层的模型就是“命令-事件”模型,没有事件处理的健壮性,意味着最终系统的健壮性无法保障,最终无法满足业务对可用性的要求。

事件的最终一致性

在我们的建模模型中,是在命令处理逻辑中,由领域模型发出事件,而事件如果要在微服务间传递,我们期望达到的效果如下:
  1. 如果命令处理逻辑成功,即对应的数据库事务提交成功,则确保事件一定能够发出;
  2. 如果命令处理逻辑失败,即对应的数据库事务回滚,则确保事件一定不发出;
在需求层面,我们并不要求系统确保事件“确定只发一次”,我们知道,这个要求的技术实现难度远远大于前面的两个要求,而且业务可以做幂等处理解决重发的问题。
下图展示了我们csharp版本中关于“命令-事件”的建模实现,以及事务的具体实现:

在我们csharp的版本,我们使用了比较流行的CAP组件,https://github.com/dotnetcore/CAP,这个组件本质上是实现了outbox模式,通常也叫“发件箱模式”,借助这个组件,我们很轻易就实现了对于事件的最终一致性。
下图来自CAP组件的介绍页面,展示了发件箱模式的具体工作原理:
从原理上看,发件箱模式并不是一个复杂的能力,我们认为一向以
生态好
为优点的Java生态,也一定有类似且流行的组件,很不幸的是,我们在互联网以及能够触达的Java圈子里调研一番之后,得出了如下结论:
  1. Java生态有关于分布式事务的实现,例如:JEE,JBoss等,但目前基本没有团队在用了;
  2. Java生态没有现成的类似CAP这样的组件可以开箱即用;
上述结论仅表示我们目前的认知和信息渠道,如果有大佬能够给指个路,不甚感激!

cap4j

基于前面的结论,为了实现Java项目的DDD代码体验实践,我们开源了一个cap4j项目,期望能将CAP项目的能力移植到Java生态,项目地址:https://github.com/netcorepal/cap4j
该项目目前实现了JPA+RocketMQ的组合,我们规划在未来支持更多的ORM和MQ中间件,同时也会支持与CAP组件的协议兼容,以实现Java、dotnet异构架构的进一步融合。也欢迎大家为项目贡献代码和想法。

最后

关于技术生态这件事,可以说Java的
生态好
,但其它语言的生态我认为也都不差,在各自的领域都有非常多的优点。我在各个评论区,总是能看到各种不切实际的偏激言论,感受到种种的恶意。期望各个语言的技术栈从业者,能够更友好地交流,大家都是软件工程师,满足业务需求,实现商业价值,才是大家的更应该关注的。

1、介绍

今天给大家推荐一款基于Node.js编写且号称下一代浏览器和移动自动化测试框架:
WebdriverIO

简单来讲
:WebdriverIO 是一个开源的自动化测试框架,它允许测试人员使用 Node.js 编写自动化测试脚本,用于测试Web应用、移动应用和桌面应用程序。能够执行端到端(e2e)、单元和组件测试,主要基于WebDriver、WebDriver BiDi和Chrome DevTools协议进行操作。功能丰富、易于使用的测试框架,支持多种浏览器和设备,并且与Selenium WebDriver API兼容。

官方网址:

https://webdriver.io/

2、主要功能和特点

  • 开源
    :WebdriverIO是一个开源项目,它使得开发者和测试人员可以在自己的项目中自由地使用和修改它。

  • 跨平台、多语言支持
    :支持多种编程语言(如JavaScript、TypeScript、Python等)和多种操作系统(如Windows、Linux、Mac OS等),确保了跨平台和跨语言的兼容性。

  • 多浏览器支持
    :WebdriverIO遵循W3C WebDriver标准,确保了与主流浏览器的无缝集成,同时支持WebDriver BiDi和Chrome DevTools协议,利用这两个强大的工具集,可以直接控制浏览器的底层功能,进行更精细的调试和测试。

  • Appium整合
    :WebdriverIO不仅支持Web应用程序的测试,还通过Appium平台提供了对Android和iOS应用的自动化支持。

  • 丰富的API和工具
    :WebdriverIO提供了一组强大的API和工具,使得开发人员能够轻松地编写和执行自动化测试脚本。这些API和工具包括遍历元素列表的方法(如$$、forEach、map、filter和reduce等),使得开发者可以灵活地进行元素操作。

  • 支持多种测试框架和断言库
    :WebdriverIO支持BDD/TDD测试框架,如Cucumber、Jasmine和Mocha,以及断言库如Chai、Expect.js等。这些支持使得开发者可以根据自己的喜好和需求选择合适的测试框架和断言库进行测试。

  • 易用性与可扩展、封装了Selenium WebDriver API
    : 与Selenium相比,WebdriverIO提供了更简洁的API,使得编写测试脚本变得更加简单易懂,尤其是对于熟悉jQuery的开发者来说。通过封装Selenium WebDriver API, WebdriverIO拥有高度的可扩展性,允许用户根据需要扩展其功能。

  • 支持多种测试模式
    :WebdriverIO不仅支持web应用的自动化测试,还支持Native移动端应用和Electron开发的桌面端应用的测试。

3、环境安装

1、安装Node.js

  • 下载与安装:访问Node.js官网
    https://nodejs.org/
    下载并安装最新稳定版的Node.js。安装过程通常是“傻瓜式”的,直接点击“下一步”直到完成即可,并确保配置到环境变量中。
  • 安装完成后,打开命令行或终端,输入node -v来检查Node.js是否安装成功,如果显示版本号,则说明安装成功。

2、初始化NPM空间

  • 在想要存放WebdriverIO项目的文件夹中(例如D盘的WebdriverIO-test文件夹),打开命令行或终端。
  • 输入
    npm init -y
    命令来初始化一个新的NPM项目空间。这个命令会创建一个
    package.json
    文件,用于管理项目的依赖包。

3、安装WebdriverIO CLI

  • 在命令行或终端中,输入
    npm i --save-dev @wdio/cli
    命令来安装WebdriverIO的命令行接口(CLI)。
  • 安装完成后,可以在
    node_modules/.bin/
    目录下找到wdio命令。但为了方便使用,建议将其添加到环境变量中,或者在命令行中通过完整路径调用。

4、生成配置文件

  • 安装完CLI后,使用
    npx wdio config
    命令来生成一个基本的配置文件
  • 执行命令后,会在项目根目录下生成一个wdio.conf.js文件,这个文件包含了WebdriverIO的配置信息

5、安装其他依赖(可选)

  • 根据您的测试需求,您可能还需要安装其他NPM包,如浏览器驱动程序(chromedriver、geckodriver等)的npm封装包。
  • 这些包可以通过npm install命令来安装,例如:
    npm install chromedriver

对于Chrome和Firefox等浏览器,您需要下载与浏览器版本相匹配的驱动程序(如chromedriver、geckodriver)。

4、编写脚本

根据
wdio.conf.js
文件中的配置项,配置项目的测试环境、浏览器、测试框架等,就可以开始编写测试脚本了。

以下是一个简单的 WebdriverIO 脚本示例,用于在百度中搜索 "WebdriverIO":

// 引入 WebdriverIO  
const { remote } = require('webdriverio');  
  
(async () => {  
    // 设置 WebDriver 的配置  
    const options = {  
        path: '/',  
        capabilities: {  
            browserName: 'chrome'  
        }  
    };  
  
    // 初始化 WebDriver 实例  
    const browser = await remote(options);  
    try {  
        // 打开百度主页  
        await browser.url('https://www.baidu.com');  
        // 在搜索框中输入搜索词  
        await browser.setValue('#kw', 'WebdriverIO');  
        // 点击搜索按钮  
        await browser.click('#su');  
        // 等待搜索结果页面加载完成  
        await browser.pause(2000); // 这里简单使用 pause,实际项目中可能需要更复杂的等待策略  
        // 获取搜索结果标题(假设是第一个搜索结果)  
        const title = await browser.getTitle();  
        console.log('搜索结果页面的标题是:', title);  

        // 关闭浏览器  
        await browser.deleteSession();  
    } catch (err) {  
        console.error('测试出错:', err);  
    }  
})();

这个示例使用了 remote 方法来初始化 WebDriver 实例,这是 WebdriverIO v5 的用法。如果你使用的是 WebdriverIO v6 或更高版本,可能需要使用不同的 API(如 new Browser())。

5、小结

综上所述,
WebdriverIO
是一个功能强大、灵活易用的自动化测试框架,适用于多种测试场景和需求。无论是新手还是经验丰富的测试工程师,都能通过WebdriverIO实现高效的自动化测试,感兴趣的读者可以尝试一下。

项目地址:
https://github.com/webdriverio/webdriverio

肉夹馍(
https://github.com/inversionhourglass/Rougamo
),一款编译时AOP组件。相比动态代理AOP需要在应用启动时进行初始化,编译时完成代码编织的肉夹馍减少了应用启动初始化的时间,同时肉夹馍还支持所有种类的方法,无论方法是同步还是异步、静态还是实例、构造方法还是属性都是支持的。肉夹馍无需初始化,编写好切面类型后直接应用到对应方法上即可,同时肉夹馍还提供了方法特征匹配和类AspectJ表达式匹配的批量应用规则。

异步切面

得益于3.0对切面实现方式的改变,4.0版本基于代理织入实现了异步切面功能。那么什么是异步切面呢?直白的说就是新增了
OnEntry/OnSuccess/OnException/OnExit
对应的异步方法
OnEntryAsync/OnSuccessAsync/OnExceptionAsync/OnExitAsync

如何使用

要编写异步切面,一般继承
AsyncMoAttribute

AsyncMo
,然后重写
OnXxxAsync
方法即可。

// 定义切面类型
public class TestAttribute : AsyncMoAttribute
{
    public override async ValueTask OnEntryAsync(MethodContext) { }
    
    public override async ValueTask OnSuccessAsync(MethodContext) { }
    
    public override async ValueTask OnExceptionAsync(MethodContext) { }
    
    public override async ValueTask OnExitAsync(MethodContext) { }
}

public class Cls
{
    // 应用到同步方法上
    [Test]
    public void M() { }

    // 应用到异步方法上
    [Test]
    public static async Task MAsync() => Task.Yield();
}

聊聊细节

在了解的异步切面的使用方式后你可能有一个疑问:同步切面在异步方法上的表现和异步切面在同步方法上的表现是什么样的?回答这个问题前,我们可以先看一下
AsyncMoAttribute
的源码:

public abstract class AsyncMoAttribute : RawMoAttribute
{
    public override ValueTask OnEntryAsync(MethodContext context) => default;

    public override ValueTask OnExceptionAsync(MethodContext context) => default;

    public override ValueTask OnSuccessAsync(MethodContext context) => default;

    public override ValueTask OnExitAsync(MethodContext context) => default;

    public sealed override void OnEntry(MethodContext context)
    {
        OnEntryAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }

    public sealed override void OnException(MethodContext context)
    {
        OnExceptionAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }

    public sealed override void OnSuccess(MethodContext context)
    {
        OnSuccessAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }

    public sealed override void OnExit(MethodContext context)
    {
        OnExitAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }
}

从源码中可以看到,
AsyncMoAttribute
是包含同步切面方法的,同时还有默认实现,实现代码就是直接调用异步切面方法,然后
GetResult
。同样的,如果你去看
MoAttribute
的源码,你就会发现,
MoAttribute
同样拥有异步切面方法,并且默认实现就是调用同步切面方法。所以,关于上面那个问题的答案就是:在同步方法中将调用同步切面方法,在异步方法中将调用异步切面方法。

此时你可能会有另一个疑问:既然
AsyncMoAttribute

MoAttribute
都拥有全部的同步切面方法和异步切面方法没什么还要分两个类呢?

这是综合便捷性和安全性考虑后的设计。正如前面所说,肉夹馍会在同步方法中将调用同步切面方法,在异步方法中将调用异步切面方法。如果不分开为两个类继续使用
MoAttribute
,那么首先一个问题:
MoAttribute
中的所有切面方法是应该设计为抽象方法让子类实现全部同步异步切面方法,还是设计为带有默认实现的虚方法让子类自由选择重写方法?

  • 选择设计为抽象方法
    设计为抽象方法就增加了子类在继承时的额外工作,需要实现所有的切面方法。

  • 选择设计为带有默认实现的虚方法
    选择这种方法就面临另一个问题:默认实现采用空方法实现,还是采用异步切面与同步切面的互调用(在异步切面方法中默认调用同步切面方法,在同步切面方法中默认调用异步切面方法)


    • 采用空方法实现
      由于是虚方法,所以子类在继承
      MoAttribute
      时并不是必须重写虚方法,所以如果重写了某个同步切面方法但是没有重写对应的异步切面方法,那么就会导致该切面类型在应用到同步方法上和异步方法上会有不同的表现,这往往是不符合预期的。
    • 采用异步切面与同步切面的互调用
      和采用空方法实现存在同样的问题,但后果却更严重。比如如果在继承
      MoAttribute
      时因为不需要在方法退出时做任何操作,所以既没有重写
      OnExit
      也没有重写
      OnExitAsync
      ,那么在方法退出时调用
      OnExit

      OnExitAsync
      时就会出现
      OnExit

      OnExitAsync
      递归调用。

从上面的说明,你应该能理解将同步切面和异步切面分为两个类型的原因了。如果你观察细致,你可能已经发现上面
AsyncMoAttribute
源码中的同步切面方法还增加了
sealed
关键字,这也是为了增加安全性,禁止重写,避免在重写方法时因IDE智能提示重写了同步切面方法而又没有重写对应的异步方法,导致出现同步切面方法和异步切面方法表现不一致的问题。

完全自定义的RawMoAttribute

既然
MoAttribute

AsyncMoAttribute
的默认实现是直接调用对应的方法,那么如果我觉得默认的实现不是最优呢,比如
AsyncMoAttribute
默认的同步切面是直接调用异步切面然后同步等待完成,我有更好的同步方案,应该怎么做呢,毕竟同步切面方法都通过
sealed
关键字禁止重写了。

细心的你在查看上面
AsyncMoAttribute
源码时可能已经发现了,
AsyncMoAttribute
继承自
RawMoAttribute
,同样的
MoAttribute
也继承自
RawMoAttribute

RawMoAttribute
开放了所有同步异步切面方法,这些方法都是抽象方法,你可以完全自定义同步异步切面。在继承
RawMoAttribute
实现同步异步切面方法时需要注意前面提到的:避免同步切面和异步切面的代码逻辑有差异,避免同步切面方法和异步切面方法出现递归调用。

其他更新内容

新增类型

除了上面提到的
AsyncMoAttribute

RawMoAttribute
,还新增了
RawMO
,
MO
,
AsyncMo
分别与
RawMoAttribute
,
MoAttribute
,
AsyncMoAttribute
对应,区别在于后者继承自
Attribute
。因为肉夹馍的应用方式除了Attribute应用,还可以通过
实现空接口IRougamo<>
的方式来应用,这种方式并不需要类型是Attribute子类,当然Attribute子类也是接受的,这里只是提供了不继承Attribute的选择。

性能优化之强制同步

在介绍异步切面时有说到:同步方法会调用同步切面,异步方法会调用异步切面。这一设定在默认情况是很好的设定,但如果你的切面操作完全不涉及异步操作,那么在异步方法中实际并不需要调用异步切面,因为异步切面走了一层
ValueTask
包装,相比同步切面会存在额外的开销。在这种情况下,可以通过
ForceSync
属性设置在异步方法中需要强制执行同步切面的方法:

public class TestAttribute : MoAttribute
{
    // 在异步方法中,OnEntry和OnExit将强制调用同步切面方法
    public override ForceSync ForceSync => ForceSync.OnEntry | ForceSync.OnExit;
}

其实,如果对性能要求并不是那么严格,是可以不去设置
ForceSync
的,肉夹馍已采用
ValueTask
,默认的异步切面方法对同步切面方法包装的额外开销十分有限。

async void的特别说明

在3.0发布时便有聊到,3.0后采用的代理织入方式对
async void
的支持可能与你的预期效果不同。具体请跳转查看
async void特别说明

考虑到
async void
是不推荐的使用方式(
官方也不推荐
),所以决定不对
async void
做更多的适配工作,继续沿用3.0的做法,将
async void
方法当做普通的
void
返回值的同步方法看待。但与3.0不同的是,在4.0版本中如果发现
async void
方法上应用了肉夹馍切面类型,将在编译时产生一个MSBuild告警。告警信息往往不容易引起注意,如果你确定自己并不希望
async void
上应用肉夹馍切面类型,或者你希望子出现这种情况时能提醒你让你做相应的修改,那么你可以在项目文件的
PropertyGroup
节点下新增一个子节点
<FodyTreatWarningsAsErrors>true</FodyTreatWarningsAsErrors>
,这个配置会让Fody产生的告警信息变为错误信息,从而使得编译失败达到提醒的目的。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <FodyTreatWarningsAsErrors>true</FodyTreatWarningsAsErrors>
  </PropertyGroup>
</Project>

MethodContext成员变化

删除
MethodContext
中的
IsAsync
,
IsIterator
,
MosNonEntryFIFO
,
Data
属性,将
RealReturnType
标记为过时并隐藏,同时新增
TaskReturnType
属性,该属性与
RealReturnType
具有类似功能。

配置文件智能提示

肉夹馍有些许可配置项,这些配置项可在
FodyWeavers.xml
中配置,详见
配置项
。现在为这些配置增加了对应的xml schema,在修改
FodyWeavers.xml

Rougamo
节点时会出现智能提示。

1.简介

上一篇中介绍和讲解、分享了Wireshark在Windows系统上安装部署,今天就介绍和讲解、分享Wireshark在MacOS系统上安装部署。Wireshark不仅是Windows系统网络协议分析软件也是一款mac网络协议分析软件,任何负责的网络分析人员都对这个软件情有独钟。如今,几乎没有哪种产品像它这样拥有如此持久的魅力,很容易看出其中的原因。网管员如果想知道自己的网络上到底在发生着什么,不妨用这款软件来捕获数据包,然后用一种易于使管理员跟踪计算机之间的会话和数据流的方式显示这些数据包。这款软件拥有大量的排序和过滤选项,供用户查找正在苦苦寻找的确切信息。

2.安装部署环境

2.1操作系统

1.宏哥的环境是Mac的版本是:12.5,其实宏哥觉得无论在什么平台,其实安装都是类似的,非常easy的。如下图所示:

2.2.软件版本

1.Wireshark的版本,宏哥在官网下载了最新的版本 4.0.2。

3.WireShark下载安装

3.1WireShark下载

wireshark的官方下载网站:
https://www.wireshark.org/
s

1.打开网址
https://www.wireshark.org
,进入 Wireshark 官网,如下图所示:

2.单击图中的下载图标进入下载页面,如下图所示:

3.点击macOS Intel 64-bit.dmg安装包,下载mac版安装包,如下图所示:

3.2安装

1.下载完成后,双击刚才下载的软件包或者将app拖到Applications中进行安装,然后Install ChmodBPF.pkg,如下图所示:

2.安装过程,如下图所示:

敲黑板!!!如果出现:“You don't hava permission to capture. You can install ChmodBPF to fix this.”,而实际第1步已经安装过ChmodBPF了。可以忽略。一般不会出现这种。如下图所示:

好了,到此,macOS系统安装部署就完成了,相比Windows系统的安装部署很简单。

4.小结

好了,今天的讲解和分享比较简单,一方面用Mac的很少,另一方面比较简单,但是还是简单说一下,比较好。今天就到这里,感谢您耐心的阅读!!!

5.拓展

如果你在Mac上使用Wireshark抓不到包,或许是因为没有权限的问题,因此授权即可解决。

那么使用 sudo chmod 777 /dev/bpf* 指令授权