C#移动跨平台工业监控应用:从设备通讯到工程化落地

Autosar Davinci Configurator新建工程以及导入DBC和CDD Autosar Davinci Configurator新建工程前言一、Autosar Davinci Configurator新建工程二、Autosar Davinci Configurator导入DBC和CDD1.引入库2.读入数据总结 前言 如何用 DavinciCFG 新建工程,以及导入DBC和CDD文件。 一、Autosar Davinci Configurator新建工程 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。 二、Autosar Davinc 阅读详情

做C#移动跨平台工业监控应用,最容易被低估的不是界面怎么做,而是设备通讯、数据采集、后台服务和移动端之间的链路怎么设计。很多人以为把一个Web页面塞进手机壳里就算“移动跨平台”,实际上工业监控真正要解决的是三件事:实时看得到、现场能操作、断网或设备异常时系统不糊掉。

这篇文章主要围绕“基于C#的移动跨平台工业监控应用”这个方向拆解,适合已经在做MES、SCADA、设备管理、车间看板,或者打算用C#统一端侧技术栈的开发者。我会重点讲清楚:跨平台框架怎么选、设备通讯层怎么封装、单机Demo和工程化实现差距在哪、上线前要验证哪些东西。文章里也会带入一些C#上位机开发、Socket通讯、扫码枪触发、串口转网络等常见场景,这些是工业监控项目里绕不开的硬问题。

1. 移动跨平台工业监控应用,技术选型到底该怎么定

1.1 先分清应用类型:移动监控看板还是现场运维工具

我在接触这类项目时,第一件事不是打开IDE写代码,而是确认应用到底属于哪一类。

有一种是“移动监控看板”,它解决的是管理层和值班人员远程查看产线状态、设备参数、告警信息。这类应用对实时性敏感,但对操作权限要求不高,大部分时间只读,偶尔确认告警。另一种是“现场运维工具”,它面向维修工和产线班组长,需要扫码枪触发、设备点检、参数下写、拍照上传、历史记录查询。这类应用对交互响应要求更高,甚至要在车间网络不稳定的环境里继续工作。

C#在这一层有一个明显优势:同一套业务逻辑代码可以被桌面端、移动端、服务端共用。只要你把通讯、采集、状态管理拆到独立项目里,界面换掉并不影响核心能力。反过来,如果一开始就把通讯逻辑写在页面代码后面,后面不管是换框架还是加新端,都会非常痛苦。

1.2 跨平台框架怎么选:MAUI、Xamarin、Blazor Hybrid还是纯Web

这个话题没有标准答案,但可以按条件筛选。

如果你的目标平台只有Android和iOS,而且希望用C#写页面,可以考虑MAUI。MAUI是Xamarin.Forms的官方演进方向,坎是全球项目比较多,网上资料比Flutter和React Native少,部分原生控件还要自己封装。

如果你的监控界面复杂度高,有大量组态、曲线、电子地图、视频流,那纯Native移动端不一定好写。这时候Blazor Hybrid是一个思路,用Web UI承载复杂图形,外层再用C#调用原生能力,比如相机、扫码枪、蓝牙。Blazor Hybrid可以在MAUI项目里使用,也可以单独做WebView宿主。

如果你的现场有Windows工控机、Linux网关、Android平板,想要的是“一套后端逻辑多处复用”,我建议不要把跨平台压力全押在UI框架上。更实际的做法是,服务层、通讯层、设备驱动层用.NET Standard或.NET类库单独成项目,移动端只做展示和输入,重活全部走API或消息通道。这样即使UI框架选错了,核心资产也不会作废。

另外要考虑团队现状。如果团队里没人写过移动端,但C#基础很好,那强行学完全陌生的跨平台语言反而更慢。用Blazor或者MAUI起码能复用C#技能,遇到问题也更容易在统一的技术栈内排查。

1.3 设备通讯的常见形态:HTTP、Socket、串口转网络

工业监控应用最终要连接的设备五花八门:PLC、传感器、扫码枪、工业相机、电表、温度采集器。从通讯协议来看,最常见的是三种。

第一种是HTTP接口。很多新设备自带RESTful API,比如工业网关、智能电表、部分视觉控制器。这种最简单,移动端直接请求,但要处理超时、认证和断网。

第二种是Socket长连接。大多数PLC网关、协议转换器、上位机中间件会提供TCP服务。现场设备把数据推上来,监控端保持连接并监听。C#里写TCP客户端很成熟,但生产环境要考虑心跳、粘包、断线重连。

第三种是串口转网络。传统串口设备通过串口服务器变成网络节点,C#程序只需要连接串口服务器的IP和端口,数据格式仍然按照原设备协议解析。这种场景在旧产线改造里非常多,比直接在移动端操作串口现实得多,因为手机本身很难直连串口。

明确这三种形态之后,你的架构方向就清楚了。移动端不需要直接理解Modbus、Profibus这些工业协议,它只需要和你的后台服务交互;真正和硬件打交道的是后端服务或者现场网关。这个拆法对技术选型影响最大。

2. 项目架构设计:设备层、通讯层、数据层、展示层怎么拆

2.1 从设备到手机,核心链路要解决哪几类问题

一个移动跨平台工业监控应用,从设备到手机至少经过四层:

  • 设备层:PLC、传感器、扫码枪、相机、采集模块。
  • 通讯层:负责和设备的连接、数据帧解析、协议转换。
  • 服务层:负责鉴权、设备管理、告警判断、历史存储、推送。
  • 展示层:手机端、平板端、桌面看板。

很多项目失败不是设备连不上,而是这四层之间没有清晰的边界。设备协议一旦变化,从界面到底层全部要改,这就是耦合过重的典型表现。

我自己的做法是:通讯层绝对不能直接引用UI层的东西,服务层不能跟具体设备型号强绑定。哪怕一开始只有一种设备,也要按“未来可能接十种设备”的方式抽象接口。工业监控项目最怕的不是首期难度,而是二期接入新设备时旧代码被推倒重写。

2.2 通讯层封装:TCP客户端、超时重连、心跳机制

如果只用HTTP轮询,很多实时监控场景扛不住。设备主动上报的场景更适合TCP长连接。C#封装TCP客户端不算复杂,但有几个点必须提前设计。

心跳机制是第一个要解决的。TCP长连接长时间没有数据,中间设备或防火墙可能把连接断开,但客户端不知道。常规做法是每10秒或30秒发一个心跳帧,服务端超过一定时间没有收到心跳就判定断线。

断线重连是第二个点。不要只做一次连接,要写成“N次失败后进入退避重试”的策略。比如第一次失败等3秒,第二次等5秒,第三次等10秒,最多等30秒。否则设备网络抖动时,客户端会疯狂重连,把服务端资源打满。

第三个点是数据帧处理。TCP底层是字节流,没有消息边界。如果直接按轮次读取,很可能会出现“半包”和“粘包”。常见解决办法是使用固定帧头、帧长度、校验位来拆包。下面是一个简化到不能再简化的TCP客户端拆包思路:

public class TcpPacketBuffer
{
    private readonly byte[] _buffer = new byte[4096];
    private int _offset = 0;

    public void Append(byte[] data)
    {
        Array.Copy(data, 0, _buffer, _offset, data.Length);
        _offset += data.Length;
    }

    public List<byte[]> TryGetCompletePackets()
    {
        var packets = new List<byte[]>();
        int start = 0;
        while (start + 4 <= _offset)
        {
            // 假设帧结构:2字节帧头 + 2字节长度 + 数据体
            if (_buffer[start] == 0xAA && _buffer[start + 1] == 0x55)
            {
                int length = ( _buffer[start + 2] << 8 ) | _buffer[start + 3];
                if (start + 4 + length > _offset)
                {
                    break;
                }
                var packet = new byte[length];
                Array.Copy(_buffer, start + 4, packet, 0, length);
                packets.Add(packet);
                start += 4 + length;
            }
            else
            {
                start++;
            }
        }
        if (start > 0)
        {
            // 把剩余字节移到头部,等待下一轮
            int remain = _offset - start;
            Array.Copy(_buffer, start, _buffer, 0, remain);
            _offset = remain;
        }
        return packets;
    }
}

这段代码只演示处理思路,实际项目中帧头、长度、校验方式都以设备协议为准。最重要的经验是:调试TCP通讯时一定要先拿测试工具独立验证,确认设备确实在发数据,再排查解析逻辑。

2.3 数据层设计:实时值、历史数据、离线缓存如何存储

工业监控数据按用途分成实时数据和历史数据。

实时数据适合放内存缓存。比如设备当前温度、转速、状态,用一个带锁的字典或者Channel就可以。要展示到移动端,一般通过WebSocket或MQTT把变化值推过去,而不是让手机每秒轮询一次。

历史数据建议单独存储。常见选择是SQL Server、PostgreSQL、SQLite。移动端如果只是查看历史曲线,通常通过接口查询,不会让手机直接连数据库。离线缓存则要考虑现场网络断开的情况。手机端可以用SQLite保存最近操作记录和告警确认信息,等网络恢复后同步到服务端。

C#在这层比较顺手。System.Text.Json序列化、Channel做生产消费队列、Sqlite-net或EF Core访问本地库,这些都是成熟方案。关键是别把所有数据都塞到同一张表里,实时数据表会越来越大,要按时间归档或分区。

3. 从单机Demo到可复现的工程实现:环境配置与基础代码

3.1 环境准备:.NET版本、开发工具、目标平台

输入材料里没有给出具体版本号,这里我给一个通用判断:建议先确认你的.NET版本和生产环境能支持到什么程度。如果是新项目,.NET 8之后的LTS版本是稳妥选择;如果还要跑Windows 7工控机,就要把目标框架降级或者用.NET Framework兼容模式。

开发工具方面,Visual Studio 2022是最省事的,自带Android、iOS的构建调试能力。注意,iOS构建在Windows下有限制,一般来说你需要一台Mac来打包或者使用远程构建服务;如果只做Android和Windows,则部署门槛会低很多。

目标平台也要提前确认。工业现场最常遇到的是Android平板、Windows工控机、偶尔有鸿蒙或纯国产系统的平板。如果你要把Android安装包发给现场,还要考虑Android版本、屏幕分辨率、是否允许未知来源安装、是否需要开机自启动。这些细节不做,Demo跑得再漂亮,部署时也会被现场环境卡住。

3.2 解决方案分层:按项目职责建项目还是按业务模块建

我见过很多人建一个解决方案,就往里面加一个“MAUI”项目,所有代码都写在页面文件夹里。前期看着方便,后期维护成本极高。

建议至少拆出五个项目:

  • Core:实体、接口、枚举、业务规则。
  • Communications:TCP客户端、HTTP客户端、协议解析。
  • Services:设备服务、告警服务、数据上报服务。
  • Application:移动端或桌面端的UI层。
  • Infrastructure:数据库访问、文件存储、日志。

这种分层看上去繁琐,但它让单元测试变得可能。通讯协议、数据解析、告警判断这些核心逻辑,完全不需要依赖界面就能跑。你可以写一个控制台程序模拟设备端,另一个控制台程序连接测试,这样能大大缩短联调时间。

3.3 一个简单的设备数据采集与推送示例

下面是一个极简的“后台服务采集设备数据,并通过API推给移动端”的示意。实际生产环境要加鉴权、日志、任务调度,这里只为展示链路。

public class DeviceReading
{
    public string DeviceId { get; set; }
    public DateTime Timestamp { get; set; }
    public double Temperature { get; set; }
    public double Pressure { get; set; }
}

采集服务里,用一个Channel把设备数据排队:

public class CollectorBackgroundService : BackgroundService
{
    private readonly Channel<DeviceReading> _channel = Channel.CreateUnbounded<DeviceReading>();

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var reading = new DeviceReading
            {
                DeviceId = "DEV-001",
                Timestamp = DateTime.Now,
                Temperature = Random.Shared.NextDouble() * 100,
                Pressure = Random.Shared.NextDouble() * 10
            };
            await _channel.Writer.WriteAsync(reading, stoppingToken);
            await Task.Delay(1000, stoppingToken);
        }
    }
}

移动端需要实时看到数据时,更建议用WebSocket或SignalR来实现推送。轮询接口的缺点是延迟高、请求量大。SignalR在C#生态里集成方便,和.NET服务端配合几乎零额外成本。如果你已经在用.NET,我建议优先考虑SignalR而不是另起一套WebSocket封装。

3.4 如何验证跨平台效果

跨平台不是说“同一份代码在所有平台长一样”,而是“核心逻辑在所有平台行为一致”。验证时至少要看四点:

  1. Android和Windows上,TCP连接、序列化、反序列化结果是否一致。
  2. 网络断开重连的行为是否一致。
  3. 时间格式和本地化是否会出现差异。
  4. UI在不同分辨率下是否不会错位。

如果核心通讯代码放在共享类库里,验证就只需要做一次。UI层即使有差异,也属于可接受范围。千万别用“真机跑通”代替“多平台跑通”,模拟器网络环境和真实车间网络差别很大。

4. 程序集B1151的设计思路:模块划分、依赖注入、消息推送

4.1 为什么用依赖注入和MVVM

题目里的B1151更像一个项目代号或产品版本标识,实际开发中我习惯把它当成一个独立工程版本来管理。既然要做工程化C#应用,依赖注入不是可选项。

依赖注入的好处是让通讯对象、设备服务、数据仓库都通过接口注册。比如写一个IDeviceConnection接口,真机上使用TcpDeviceConnection,测试时使用MockDeviceConnection。这样在单元测试里不需要真实设备,也能验证告警逻辑是否正确。

MVVM模式对跨平台移动端尤其重要。ViewModel层负责把原始设备数据转换成界面可以绑定的对象,View层只做显示。比如温度超过80度时,需要显示红色告警状态,这个判断应该放在ViewModel里,而不是写在界面的后台代码里。否则Android和Windows两个端会各写一遍,很容易出现行为不一致。

4.2 状态管理:设备在线、告警、采集值如何统一

工业监控最怕状态混乱:设备明明断线了,界面还显示正常;告警已经恢复了,记录里还是告警中。这些问题往往不是设备的问题,而是状态管理没有做单一数据源。

建议在服务端维护一个DeviceState对象,包含:

  • ConnectionState:在线、离线、正在连接。
  • LastHeartbeatTime:最后一次心跳时间。
  • LastReadingTime:最后一次采集时间。
  • AlarmLevel:无、提示、警告、严重。
  • AlarmDescription:当前未恢复的告警描述。

移动端不要自己独立判断设备是否在线,应该由服务端根据心跳和采集超时统一计算。客户端只是展示服务端下发的状态。

4.3 移动端推送和桌面端的差异

桌面端监控看板可以常驻页面,通过SignalR实时刷新;移动端则需要考虑锁屏、后台杀进程、弱网切网这些情况。如果只是App处于前台时看数据,那普通WebSocket就可以。但如果你想在App退出后还能收到报警通知,就要接入系统级推送,比如Android的FCM或厂商推送,iOS的APNs。

这里常见的一个认知误区是:把“实时通信”和“离线推送”混为一谈。实时通信是App活着的时候收消息;离线推送是App死了之后系统还能收到消息。工业监控项目里,离线推送更适合用在“严重告警”场景,而不是把每个测温波动都推给用户。推送频率过高,反而会让值班人员忽略真正重要的告警。

5. 设备通讯稳定性:扫码枪触发、Socket、工业协议的经验

5.1 C#中处理扫码枪触发的思路——不是技术多难,是事件源要理清

相关工作热词里频繁出现“c# 扫码枪触发事件”,说明这个场景在C#开发里很常见。扫码枪在工业现场有两种模式:键盘模拟模式和串口/网络模式。

键盘模拟模式最简单,扫码枪相当于一个键盘,扫码后连续输入一串字符并以回车结尾。C#里监听全局键盘事件可以做到,但这会让应用变成“全局监听”模式,容易误触发。更好的做法是聚焦到输入框,让扫码枪把内容输入到指定控件后触发回车键。这样代码简单,也不会干扰别的窗口。

串口或网络模式更可靠。如果扫码枪支持串口或TCP输出,就让服务端上建立连接去读取扫码结果,再通过内部消息把数据推给移动端。这种方式不受键盘焦点限制,但你需要自己处理断线重连。现场扫码枪长期带电运行,掉线是难免的,代码一定要考虑掉线后能自动恢复。

还有一个经常踩的坑:扫码内容是UTF-8、GBK还是ASCII。在Windows工控机上GBK司空见惯,到Android平板上编码不一致就会出现乱码。统一在设备接入层做编码转换,不要等页面拿到数据后才发现不对。

5.2 Socket通讯常见问题:粘包、断线重连、多客户端并发

如果你在上位机或者后台服务中直接使用Socket,一定会遇到粘包问题,除非每个设备单独一个TCP连接、每次通讯都短暂断开。持久连接下,设备可能一次性发送多个数据帧,也可能一个帧分几次到达。用前面的拆包缓冲处理能解决大部分问题。

断线重连要区分主动断开和被动断开。服务端关闭时,客户端要能识别“服务端正常关闭”;设备断网、断电时,则会表现为长时间收不到数据或收到RST包。客户端要基于心跳超时做判断,而不是只在收到异常时才重连。

多客户端并发又是另一个层级。如果你写的是网关系统,一台服务端要管理几十台设备,就不能给每个设备开一个裸线程。应该用异步I/O或者独立连接管理器。.NET的Socket在异步模式下性能不错,关键是不要用后台线程死循环去读,要基于事件或async/await处理。

5.3 串口和Modbus等工业协议的接入思路

传统工业协议底层的字节拼装并不难,难的是协议变体多、端序不一致、寄存器地址位号不统一。以Modbus为例,有RTU、ASCII、TCP三种模式,同样一个寄存器,有的设备支持读保持寄存器,有的支持读输入寄存器,有的地址从0开始,有的从1开始。

建议把“协议解析”和“设备业务含义”分开。协议层只负责字节收发和校验,业务层负责把寄存器地址映射到设备参数。假设卧式设备A和B都用Modbus,但A的温度存在寄存器100,B的温度存在寄存器200,你只需要在配置表里改地址,不应该改代码。

串口转网络的场景,手机端一般无法直接操作串口,要通过服务端中转。服务端负责和串口服务器保持TCP连接,读完数据后转换成业务数据,再通过接口或消息队列交给移动端。这样移动端只面对一套网络协议,设备侧无论怎么变,都隔离在后台服务里。

6. 现场部署与问题排查:上线前要做的验证清单

6.1 先跑通最小链路:设备-服务端-移动端

不管功能规划得多复杂,第一版上线前必须跑通一条最小链路:设备上报数据,服务端解析入库,移动端展示实时值并收到告警。

最小链路跑通后,再做三件事:

  1. 断开设备和服务端之间的网络,确认断线告警能在规定时间内产生。
  2. 恢复网络,确认设备和服务端能自动重连,且数据恢复正常。
  3. 杀掉移动端App后台进程,重新打开,确认最新数据能从服务端拉回来。

这三件事件只要有一件不通过,就不要谈批量并发和高级功能。工业监控应用的第一指标是可靠,不是功能多。

6.2 网络环境差异:同一局域网、跨网段、4G/5G

开发时大部分时间在同一个局域网里,网络质量稳定。现场则可能遇到:设备在A车间,服务器在信息中心机房,手机端走Wi-Fi或4G,中间经过交换机、防火墙、路由器。跨网段时,TCP长连接有可能被防火墙的会话超时机制断开,心跳间隔要设置得比防火墙超时时间短,否则看起来连接还在,实际已经断开。

另外,现场Wi-Fi往往不如家庭路由器稳定。车间里金属结构多,信号衰减快,平板和AP之间可能出现频繁漫游。移动端要能容忍网络抖动,不要一断网就弹错误框,更不要直接崩掉。可以做一个在线离线状态提示,让用户知道当前数据是否最新。

6.3 常见问题排查顺序

如果你在C#工业监控项目里遇到问题,我建议按下面的顺序排查,不要一上来就怀疑协议或者框架:

  1. 先确认服务是否在跑。进程是否退出、端口是否监听、日志是否还在输出。
  2. 再确认设备是否在发数据。用网络抓包工具看有没有数据包到达。
  3. 再确认数据内容是否符合协议。帧头、长度、校验和、大小端是否匹配。
  4. 再确认配置是否正确。设备IP、端口、超时时间、设备号是否填错。
  5. 最后再怀疑代码逻辑。此时加上详细日志,记录原始字节流和解析结果。

这个顺序能帮你少走很多弯路。很多“看起来像代码问题”的情况,实际是现场网线松动、设备断电或者配置被改过。

6.4 日志与监控:上线后怎么快速定位

工业监控应用上线后,没有日志就等于盲飞。我建议在服务端至少记录以下几类日志:

  • 设备连接日志:什么时间连接,什么时间断开,是否重连成功。
  • 原始报文日志:设备上行和下行数据的关键帧,方便回放。
  • 业务操作日志:谁在什么时间确认了哪条告警。
  • 异常日志:堆栈、参数、上下文信息。

移动端也要记录日志,尤其是页面跳转、接口请求失败、Socket断开这类关键节点。现场人员遇到问题时,第一反应通常不会说清楚操作步骤,你把日志导出后再分析,效率要高得多。移动端日志建议写到本地文件,同时支持手动上传,不需要为日志功能再建一套复杂后台,但至少要有文件输出和导出入口。

通常我在上线前,会专门拿出半天时间模拟各种故障:拔网线、断设备电、改错IP、非法数据包、超大并发。把这些故障全部逼出来并逐一修复后,现场运行才会稳定。否则你以为的“小概率故障”,在7x24小时产线面前会变成每天都能看到的日常问题。

如果你正准备落地一个C#移动跨平台工业监控应用,我的建议很直接:先不要急着做界面,把设备通讯、数据链路和服务端状态管理做扎实。界面随时可以换,通讯层一旦坑下去,返工成本非常高。整个项目最值得投入精力的地方,也正是这些看起来不够“炫酷”的部分。

YOLOv11改进策略【卷积层】| CVPR-2024 PKI Module 获取多尺度纹理特征,适应尺度变化大的目标 PKI Module是。 阅读详情

相关推荐

SAP采购订单行项目增强实战:用BADI ME_GUI_PO_CUST添加自定义字段(避坑指南)

本文详细解析了如何通过BADI ME_GUI_PO_CUST在SAP采购订单行项目中添加自定义字段,包括技术架构理解、字段扩展步骤、自定义函数组创建及BADI实现。文章特别强调了避开官方文档未提及的陷阱,如字段映射限制和屏幕显示问题,并提供了高级优化技巧和性能建议。

weixin_30402343的博客 595

Labview对控件操作时不易发现的错误总结。

1:控件的有标签和标题两个属性,但只能通过标签来查找控件;2:在一个VI中,同一类型的控件标签不能一样。

weixin_41413693的博客 5244

什么是PCIe Relaxed Ordering

什么是PCIe上的Relaxed Ordering呢?直接翻译的话就是宽松排序。在理解这个东西之前,需要先了解下什么是PCIe的基本事务排序法则。

qq_42824983的博客 1511

Linux学习笔记(5)Vim程序编辑器

vim welcome.txt//自动生成welcome文件并打卡vim编辑器 会生成一个这样的文件,之后再次用上述指令打开则会提示 改为 vim welcome.txt.swp// 则不会有提示出现。

sakaili的博客 384

Echocardiography Image Segmentation: A Survey(超声心动图图像分割方法综述--中文翻译)

Echocardiography Image Segmentation: A Survey 摘要:尽管超声图像的获取是较廉价,并且免于辐射的,但是超声图像因为信号衰减、斑点噪声等干扰,使得超声图像的分割具有较大挑战。本文将近些年应用于超声心动图像分割的相关方法进行了分类总结,并列出了10篇具有原创思想的文章,这些文章具有特殊的临床使用价值或是对于超声心动图像分割具有指导意义。 关键词:超声心动...

mrj4124的博客 5098

DDS信号发生器设计避坑指南:从AD9834配置到巴特沃斯滤波实战

本文详细解析了基于AD9834芯片的DDS信号发生器设计中的关键技术要点与常见陷阱,涵盖时钟源选择、寄存器配置时序、巴特沃斯滤波器设计等核心内容。针对中高频段信号质量优化,提供了实用的解决方案和代码示例,帮助工程师规避设计误区,提升信号发生器的性能和稳定性。

2y3u4i5o6p的博客 782

vi编辑器

什么是vi linux中一个最重要的文本编辑软件 vi是一种模式化的文本编辑工具 vi的工作模式 模式1:编辑模式 这是打开文件后的默认的模式 编辑模式不可以在文件中写入和删除内容 模式2:输入模式 这种模式才可以在文件中写入、修改、删除内容 模式3:末行模式 这种模式可以执行各种的命令,例如保存退出、显示行号 模式转换 编辑模式 --->输入模式 【i】 输入模式--->编辑模式 【ESC】 编辑模式 --->末行模式 【shift+:】 末行模式--->编辑模.

m5426的博客 1265

某Z节验证码

某Z节验证码、captchaBody、滑块、旋转、空间推理

mamenqi_csdn的博客 773

vi命令的使用方法

在Linux系统中,用来编辑文本文件,用得最多的工具估计得数vi了。 语法:vi 如果给出的路径的文件不存在,它会自动新建一个。 vi分为编辑模式和非编辑模式,这个很好理解,编辑模式就可以像记事本一样编辑里面的内容,非编辑模式只能查看,就像看pdf一样。 这里分别列出一些常用的操作。 默认打开vi时,进入的是非编辑模式,可以按

962

Win10或Win11电脑找不到以太网网络适配器的解决方法

Win10或Win11电脑找不到以太网网络适配器的解决方法

Robot_PLC_HMI_Automation 655

Python爬虫实战:模拟登录知乎 – 通过加密参数和验证码实现自动登录

通过本篇博客的讲解,我们学习了如何通过 POST请求 和 验证码识别,模拟登录知乎并爬取用户信息、问题数据。随着爬虫技术的发展,面对更复杂的反爬虫机制,我们可以不断调整策略,以绕过这些防护,实现数据的自动化抓取。

2201_76125261的博客 731

枚举的性质及其方法的使用~

枚举的性质及其方法的使用~

qq_57603004的博客 454

SAP BTP ABAP RAP 开发对象命名规范与落地实践

摘要:SAP BTP ABAP开发中的命名规范实践 在企业级ABAP开发中,命名规范是提升交付效率的工程化手段。SAP推荐采用[/<namespace>/][<prefix>]_<object_name>_[<suffix>]的结构化命名框架,解决多对象、多团队的协同问题。关键实践包括:使用组织专属命名空间避免冲突;通过prefix区分同类型对象的不同语义(如UI_/API_);object_name体现业务语义而非技术细节;suffix表达次级差异。在具体对

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1435

vi编辑器命令

vi是一个命令,也是一个车命令行下的编辑器, 它有如下功能:• 打开文件,新建文件,保存文件• 光标移动• 文本编辑• (多行间 | 多列间)复制,黏贴,删除• 查找和替换很多人不习惯在命令行下编辑文件,在实际开发中也不会经常在命令行下编辑文件. 但是在Linux系统中对文件做些简单修改时, 使用vi命令的效率非常高,并且在很多时候,比如现场调试,并没有GUI形式的编辑工具,vi是唯一选择.

qq_57484399的博客 8506

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Linux之vi编辑器

文章目录前言一、vi的三种运行模式1.普通模式2.插入模式3.命令行模式二、vi的使用1.进入vi2.普通模式下的光标定位二、使用步骤1.引入库2.读入数据总结 前言 vi是Visual interface 的简称,可以执行输出、删除、查找、替换、块操作等众多文本操作,而且用户可以根据自己的需要对其进行定制,这是其他编辑程序所没有的功能。 提示:以下是本篇文章正文内容,下面案例可供参考 一、vi的三种运行模式 vi有三种基本模式:普通模式、插入模式和命令行模式 1.普通模式 进入vi之后就是普通模式(这

m0_56581199的博客 9869

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Vi编辑器的使用方法及用vi编辑器编写一个C程序

一、Vi编辑器的介绍 Vi编辑器是ubuntu最基本的文本编辑器。 有三种工作模式: 命令模式:键盘接收的任何字符都被当做命令来解释,不会出现在屏幕上。 插入模式:进行文本编辑 末行模式:在屏幕底部显示 “ :”,等待用户输入命令。 三种模式的切换方法: 命令模式→输入模式: i:在当前光标所在字符的前面,转为输入模式      I:在当前光标所在行的行首转换为输入模式      a:在当前光标所...

zy2018A14118的博客 8184

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

vi/vim编辑器入门

前言:前段时间接触了这个vi编辑器,第一次用也是一脸懵比,花点时间学习了下基本操作,用惯了图形界面感觉还是挺新颖的。 简介:vi编辑器是所有Unix及Linux系统下标准的编辑器,对Unix及Linux系统的任何版本,vi编辑器是完全相同的。vim是vi的升级版,增加了一些功能,对vi命令是完全兼容的。在一些基本命令上两者应该是一样的。 一、vi/vim的三种模式 vi编辑器有三种模式:命令...

老王の博客 4万+

Linux 之 Vi 编辑器

Vi 编译器

阿干tkl的博客 6453

vi编辑器 末尾添加_VI编辑器的使用方法

一、vi的工作模式vi有两种工作模式:编辑模式:用来输入和编辑文件的模式,屏幕上会显示用户的键入,按键不是被解释为命令执行,而是作为文本写到用户的文件中。指令模式:用来编辑、存盘和退出文件的模式。运行vi后,首先进入指令模式。此时输入的任何字符都被视为指令,键入的命令不会在屏幕上显示。从指令模式切换到编辑模式,则可以按“Insert”键或“i”键,从编辑模式切换到指令模式,可按“Esc”键。状态行...

weixin_39641231的博客 3309

Linux中vi编辑器的使用方法

一、认识vi编辑器 概念: vi是一个功能强大的全屏幕文本编辑器,是linux上最常用的文本编辑器,它的作用就是建立、编辑、显示、查看文本文件。 vim编辑器是从vi上发展出来的一个性能更加强大的文本编辑器。可以主动的以字体颜色辨别语法的正确性,方便程序设计。vim和vi编辑器完全兼容。 2.vi没有菜单,只有命令。(只能通过命令,来下达指令,来进行编辑操作)。 3.语法:Vi 文件名 文件名必须有, 若文件存在,打开编辑,如果不存在,则会先创建文件,再打开 4.vi编...

m0_57202083的博客 7948

vi编辑器使用

vi编辑器使用

小何的博客 1520

vi编辑器的使用

1、vi编辑器三种模式的切换 2、光标移动 3、复制、粘贴、删除、撤销 4、查找和删除 5、vi难点讲解和实例演示vi操作

m0_60532656的博客 7915

【linux】vi编辑器

vi \ vim 是 visual interface 的简称,是 Linux 中最经典的文本编辑器同图形化界面中的 文本编辑器 一样,vi 是命令行下对文本文件进行编辑的绝佳选择。vim 是 vi 的加强版本,兼容 vi 的所有指令,不仅能编辑文本,而且还具有 shell 程序编辑的功能,可以不同颜色的字体来辨别语法的正确性,极大方便了程序的设计和编辑性。windows文本编辑器:什么是vi/vim编辑器vi \ vim 编辑器,就是命令行模式下的文本编辑器,用来编辑文件。

JackCao_Grass的博客 872

vi编辑器介绍以及vi的使用规则

vi编辑器 (一)Vi编辑器的概念: vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强 大不逊色于任何最新的文本编辑器,Vi是Linux中最基本的文本编辑器,用于编辑任何ASCII文本,对于编辑源程序尤其有用,学会它后,将在Linux的世界里畅行无阻。 基本上vi可以分为三种工作模式,分别是 命令模式(command mode)、插入模式(Insert mode)、末行模式(

liuzuyi200的专栏 1915

常用vi编辑器命令

最近经常用到vi编辑器,作个记录,以后需要便于查询 常用操作 命令 作用 h 游标左移 j 游标下移 k 游标上移 l 游标右移 w 向前移动一个单词 b 向右移动一个单词 e 向前移动一个单词,游标指向单词末尾 ( 移动到当前句子的首部 ) 移动到下一个句子的首部 { 移动到当前段的首部 } 移动到当前段的尾部 0 移动到当前行的首部 ...

Eicky 4万+

VI编辑器之删除操作

1、vi列删除 方法一: ctrl+v进入列编辑模式; 将光标定位子想要删除的起始列; 移动光标至结束列(直接通过移动光标选中,对列不对齐时,可能比较长的行,无法全部选中,尤其是需要一直删除到行末,按end可直接到达,在列不对齐情况下也可将内容全部选择) 方法二: 1.定位光标; 2.按d; 3.按ctrl+v; 4.按end(直接到行末)或数字+方向键(指定需删除的字符数)

A670449625的专栏 2万+
上一篇: ComfyUI终极中文整合包:从节点可视化到AI绘画工作流工程实践
下一篇: 前端后端环境BUG定位:一条通用的分层排查方法论
weixin_34026276
博客等级 码龄11年 6372粉丝 1272原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值