news 2026/10/14 15:11:53

MCP实战:构建AI操控Excel的后端服务全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MCP实战:构建AI操控Excel的后端服务全解析

前段时间有个做运营的朋友抱着一摞Excel表格找我,说他们想用AI把这些表“管起来”——不是问一句“这个表有多少行”这种回答,而是像让AI替班干活的形态:你说一句“把销售明细里华东区订单金额大于5000的提取出来,按省份汇总,写进新工作表”,它就把文件改好放回原处。市面上主流AI助手聊起天来头头是道,但真要让它们动手改表,基本都停在“读取能力”,写不回去。问题出在少了一条AI与文件之间“动手干活”的通道。这条通道,最后我用MCP(Model Context Protocol,模型上下文协议)自己搭好了,这就是我的第一个MCP服务——一个专门给AI操作Excel用的后端服务。

这篇稿子会从协议设计的角度讲清楚MCP到底在解决什么问题,再按我实际开发的顺序,把工具梳理、代码实现、客户端配置、真实排障和扩展方向都说一遍。不管你是打算用Python搭一个个人效率工具,还是想在团队内部做一套“AI数据助理”,这套思路都能直接参考。

1. 为什么偏偏是MCP:Excel自动化缺的是一个标准接口

1.1 传统方案的三个坑

在MCP出现以前,要让AI和Excel扯上关系,常规路数无非三种。

第一种是VBA宏。这个东西在本地处理固定格式表格确实好用,但它是“单机脚本”,AI没法直接调用它,你依然要靠人肉触发,而且维护起来很痛苦。第二种是用RPA录制鼠标键盘,字段一变化、表格结构一调整,流程就断掉,维护成本高到想骂人。第三种是写Python脚本,每个需求写一段,从“读取文件”到“生成报告”一次性串起来,看似灵活,但脚本之间无法复用,AI需要用的时候还得人去拼接参数,实际上并没有把AI从“写代码的人”变成“调度工具的人”。

这三种方案有一个共同病根:工具和AI模型之间没有标准协议。你要么把整个业务逻辑写死在代码里,要么每次手工手工地配合,都谈不上“让AI自主干活”。

1.2 MCP是什么,别再把它和硬件协议混在一起

有个朋友问过我一个挺有意思的问题:“MCP到底是软件协议还是硬件协议?”这名字跟“硬件上下文”之类的东西确实容易混。我更喜欢用一个比喻解释:硬件世界里的USB-C口,统一了充电、数据、视频输出这些完全不同的功能,插上就能用;而MCP就是软件世界里的“USB-C口”,它统一了AI模型与外部工具、数据源之间的连接方式。规范地讲,MCP属于应用层软件协议,底层消息走的是JSON-RPC 2.0。

在MCP的架构里有几个角色需要分清楚:MCP Host是AI应用本身,比如Claude Code、Cursor这类客户端;MCP Client负责在Host里维持与Server的会话;MCP Server则是真正执行工具、暴露资源的一方。简单说,Server提供“工具清单”,Client负责把清单呈现给模型,模型根据用户问题选择合适的工具去调用,Server再返回结果。这和传统Function Calling最大的区别在于:Function Calling的函数是提前写死在应用进程里的,而MCP把工具变成了一套可发现、可插拔的服务,换一个客户端也能用同一套工具。

1.3 AI操作Excel的边界在哪里

有人可能会问:“AI真的能像人一样打开Excel、点击单元格吗?”答案是它不会打开界面,它通过我暴露的工具函数直接读写文件。听起来很简单,但这个边界实际上决定了项目安全设计:AI不会用鼠标,但它会调用read_sheet读文件、write_cell改单元格、save_summary生成汇总表。这些能力加起来,已经覆盖了日常80%的表格处理需求。

而且,这种模式反而更安全——你完全控制AI可以碰哪些文件、不能碰哪些文件。把工具按“读取、写入、统计、导出”这几个方向拆开,再挂在MCP Server上,AI就像一个有权限且能自主思考的执行者。这比给AI开一个Excel COM接口让它胡乱点要靠谱得多。

2. 动手前的选型:技术栈、目录结构和依赖

2.1 技术栈对比,我为什么选Python

选型时我认真对比了三个方向,结果差异还挺明显的。

方案优势劣势
Python + MCP SDK + pandas/openpyxl生态最成熟,数据处理能力极强,SDK文档多部署环境需要Python,正式使用前要处理好依赖
Node.js + MCP SDK + exceljs前端团队友好,启动快复杂公式、大数据量处理不如pandas顺手
低代码/RPA平台上手快,拖拽配置难以跟主流AI客户端深度集成,扩展性受限

我最终选了Python。原因是Excel日常处理里,pandas的筛选、分组、聚合能力几乎是降维打击,而openpyxl又能保住原始文件的样式和公式。MCP官方对Python的支持也非常完善,FastMCP接口写起来简单,一套代码下来不用绕弯。

2.2 项目结构设计

做工具类项目,最忌讳把所有代码堆在一个文件里。前期工具少不觉得,等加到七八个工具之后,你会被自己的代码逼疯。我的项目结构如下:

excel-mcp/ ├── server.py # MCP入口,注册所有工具 ├── config.py # 白名单目录、备份路径等配置 ├── tools/ │ ├── __init__.py │ ├── read_tool.py # 读取类工具 │ ├── write_tool.py # 写入类工具 │ ├── analyze_tool.py # 统计汇总类工具 │ └── export_tool.py # 导出/转换类工具 ├── data/ # 允许AI读取的Excel白名单目录 │ └── samples.xlsx └── requirements.txt

为什么强调白名单目录?因为MCP Server一旦跑起来,它就有了文件系统访问权限。如果不加限制,AI被恶意诱导去读取本地敏感文件是完全可能的。把data/作为唯一允许操作的工作目录,相当于给AI画了一个可控的“工作区”,这是我在安全设计上最后悔应该早点做的事,建议任何人都别省。

2.3 依赖安装与版本提醒

依赖只需要三个核心包:

pip install mcp pandas openpyxl

我把mcp这个官方包装好之后,直接用FastMCP类快速搭建服务,比手写底层协议代码省太多事。这里提醒一句:MCP的Python SDK最近迭代不算慢,如果你发现某些接口跟网上教程对不上,优先查看当前安装版本的help(),别盲目抄老代码。兼容性这事,做AI项目尤其常见。

3. 核心实现:从read_excel到analyze_data的工具开发

3.1 工具清单怎么定

MCP Server的本质,是给AI提供一份可调用的“能力清单”。这份清单的质量直接决定了AI能不能完成你的需求。我的原则是:工具越原子化越好,每个工具只做一件事,参数尽量少,让AI没那么多“自由发挥”的空间。

我一开始只设计了三个工具:

工具名作用
list_sheets列出Excel文件里的所有工作表名称
read_sheet读取指定工作表前N行数据
write_cell在指定工作表写入/修改单个单元格

跑通之后,我又补了三个生产环境必用的:

工具名作用
filter_rows按某列关键词筛选行
sum_by_keyword统计某列含关键词的行,对另一列求和
save_summary按分组列做分组汇总并保存为新工作表

工具数量并不是越多越好。工具太多会扰乱AI的判断,工具太少又会限制它能做的事。先从3个最基础的开始,验证链路通了再迭代,是成本最低的方式。

3.2 read_sheet:一切的起点

第一个必须写的工具是读取。没有读取,后续任何一个分析都无从谈起。代码我放在了tools/read_tool.py里:

import os import pandas as pd def read_sheet(file_path: str, sheet_name: str = None, max_rows: int = 50, max_cols: int = 20) -> dict: """ 读取指定工作表中的数据,默认只读前50行,防止输出过大。 """ if not os.path.exists(file_path): return {"error": f"文件不存在: {file_path}"} try: df = pd.read_excel(file_path, sheet_name=sheet_name, nrows=max_rows) except Exception as e: return {"error": f"读取失败: {str(e)}"} df = df.iloc[:, :max_cols] # 把NaN转成字符串,否则AI拿到float('nan')会一头雾水 df = df.fillna("").astype(str) return { "file": file_path, "sheet": sheet_name or "默认工作表", "rows": len(df), "data": df.head(max_rows).to_dict(orient="records") }

注意两个细节。一是fillna("").astype(str),这一步非常重要,AI拿到混合了数字、空值和字符串的数据时,如果直接返回原始类型,它反而容易推理出错,全部转成字符串最干净。二是to_dict(orient="records"),把DataFrame转成列表套字典的结构,AI读起来就像一个JSON,轻量又直观。

3.3 write_cell:改文件之前先备份

写入工具是整个服务里风险最高的一个,因为一次错误写入可能毁掉源文件。我利用openpyxl直接操作workbook,尽量避免用pandas的to_excel覆盖,那样会把原有的公式样式全丢掉。

import shutil from openpyxl import load_workbook def write_cell(file_path: str, sheet_name: str, row: int, col: int, value) -> dict: """ 写入单个单元格。row/col从1开始计,符合Excel习惯。 """ backup_path = file_path + ".bak" shutil.copy(file_path, backup_path) # 写之前先备份 wb = load_workbook(file_path) ws = wb[sheet_name] if row < 1 or col < 1: return {"error": "行号和列号必须从1开始"} ws.cell(row=row, column=col, value=value) wb.save(file_path) return { "status": "ok", "file": file_path, "location": f"{sheet_name}!{row}:{col}", "value": value, "backup": backup_path }

之所以每次写入都复制一份.bak,是因为AI调用工具时,没人能百分百保证它理解对了你的意图。写坏了,你还能从备份文件找回原数据。这个成本很低,但能救命。

3.4 sum_by_keyword:一个真实需求的落地

有个场景你可能特别熟:Excel一列里有各种订单备注,想统计所有带“华东”关键词的订单对应金额总和。最开始我自己也是靠筛选再手动求和,后来干脆把这件事做成了一个MCP工具。

def sum_by_keyword(file_path: str, sheet_name: str, column: str, keyword: str, sum_column: str) -> dict: """ 统计列column中包含keyword的行,对sum_column列求和。 """ df = pd.read_excel(file_path, sheet_name=sheet_name) if column not in df.columns: return {"error": f"列 {column} 不存在"} if sum_column not in df.columns: return {"error": f"列 {sum_column} 不存在"} mask = df[column].astype(str).str.contains(keyword, na=False) matched = df[mask] total = matched[sum_column].sum() return { "keyword": keyword, "matched_rows": len(matched), "sum_total": round(float(total), 2) }

这个工具看起来简陋,但它是“自然语言需求”到“具体操作”之间最典型的翻译。用户对AI说“统计华东区的总金额”,AI负责把“华东区”映射到关键词、把列名对应起来,然后调用sum_by_keyword返回结果。如果没有这种明确的原子工具,AI就得自己拼代码,出错概率会直线上升。

3.5 用config.py限制工作区

最后在config.py里加上白名单:

import os WHITELIST_DIR = os.environ.get( "EXCEL_WHITELIST_DIR", os.path.join(os.path.dirname(__file__), "data") ) BACKUP_DIR = os.path.join(os.path.dirname(__file__), "backup") def is_allowed(file_path: str) -> bool: """检查文件是否在白名单目录内""" file_path = os.path.abspath(file_path) allowed = os.path.abspath(WHITELIST_DIR) return file_path.startswith(allowed)

每个工具函数在真正执行前,都应该先调用一次is_allowed。这是安全底线,也是我吃过亏才加上的:一开始图省事没做限制,测试时AI差点把临时目录下一个同名文件读错。

4. 把服务跑起来:客户端配置与Codex接入

4.1 MCP Server的入口代码

把工具函数注册成MCP工具的方式很简单:

import asyncio from mcp.server.fastmcp import FastMCP from mcp.server.stdio import StdioServerTransport from config import is_allowed from tools.read_tool import read_sheet from tools.write_tool import write_cell from tools.analyze_tool import sum_by_keyword mcp = FastMCP("excel-mcp") @mcp.tool() async def tool_read_sheet(file_path: str, sheet_name: str = None, max_rows: int = 50, max_cols: int = 20) -> dict: if not is_allowed(file_path): return {"error": "文件不在白名单目录内"} return read_sheet(file_path, sheet_name, max_rows, max_cols) @mcp.tool() async def tool_write_cell(file_path: str, sheet_name: str, row: int, col: int, value: str) -> dict: if not is_allowed(file_path): return {"error": "文件不在白名单目录内"} return write_cell(file_path, sheet_name, row, col, value) @mcp.tool() async def tool_sum_by_keyword(file_path: str, sheet_name: str, column: str, keyword: str, sum_column: str) -> dict: if not is_allowed(file_path): return {"error": "文件不在白名单目录内"} return sum_by_keyword(file_path, sheet_name, column, keyword, sum_column) async def main(): transport = StdioServerTransport() await mcp.run(transport=transport) if __name__ == "__main__": asyncio.run(main())

注册工具用的是@mcp.tool()装饰器,函数名、参数名和docstring都会变成AI可识别的“工具说明”,所以参数命名一定要自解释。StdioServerTransport表示通过标准输入输出与客户端通信,这也是大多数本地MCP客户端默认的方式。

4.2 客户端的MCP配置文件

写好Server之后,需要在客户端里注册。不同客户端的配置文件位置略有不同,但配置格式基本统一,核心是告诉客户端用哪条命令启动Server:

{ "mcpServers": { "excel": { "command": "python", "args": ["/Users/me/excel-mcp/server.py"], "env": { "EXCEL_WHITELIST_DIR": "/Users/me/excel-mcp/data" } } } }

注意,客户端的“工作目录”和当前系统PATH未必包含python命令,尤其在macOS上经常是python3。最稳妥的做法是把command改成绝对路径,比如/usr/local/bin/python3,避免客户端找不到解释器。配置完成后,重启客户端让MCP配置生效。

4.3 Codex接入踩坑:找不到MCP怎么办

“Codex无法找到MCP”这个问题在社区里出现频率极高。我接入的时候也卡了一晚上,归纳下来最常见的五个原因:

  1. 配置文件位置不对。不同版本Codex读取的配置文件不完全一样,有时候是全局配置,有时候是项目目录下的.mcp.json,先确认你改的文件真的是当前会话会读的那个。
  2. 改配置之后没重启会话。MCP Server列表通常只在客户端启动时加载一次,改了配置要完整重启。
  3. command不可执行。如果你写的是python,而Codex启动环境里没有Python的PATH,它当然拉不起Server。用which python找到绝对路径填进去。
  4. Server启了但立刻崩掉。打开客户端日志或者终端手动跑一遍python server.py,看有没有语法错误、缺少依赖、路径不存在之类的启动报错。
  5. 环境变量没传过去。白名单目录、API Key这类配置写在env字段里,但如果漏写或写错,工具内部的is_allowed就会拒绝。

排查顺序我建议是:先从终端手动启动Server验证代码本身没问题,再确认配置里的command和args可以组合运行,最后才去看客户端日志。如果你发现Server明明起来了但工具列表还是空,多半是docstring或函数签名写得不标准,客户端无法正确解析工具描述。

4.4 用mcp dev做可视化调试

MCP官方提供mcp dev命令,用来在浏览器里直接调试Server:

mcp dev server.py

它会启动一个本地调试面板,展示当前Server暴露了哪些工具、可以手动传入参数并观察返回结果。这是我开发时用到最多的功能,因为它能在不经过AI客户端的情况下,验证每个工具函数本身的逻辑是否正确。等工具函数全部验证通过,再回客户端里接入AI,排查问题的范围就小很多。

5. 实战现场:从加载项被禁用到AI改表格的典型流程

5.1 加载项被禁用了?MCP方案不需要装Excel插件

有很多人在用Excel时遇到过“加载项被禁用”的提示,一些需要靠COM加载项或VBA宏才能用的功能直接被卡死。MCP的优势恰恰在于,它完全不在Excel进程内运行。我们的Server是一个独立进程,用pandas/openpyxl直接读写xlsx文件,跟Excel界面加载项、宏安全设置没有任何关系。

这意味着哪怕Excel里加载项全线阵亡,只要你能拿到文件路径,AI照样能完成读取、清洗、统计、回写。我实际帮朋友处理表格时,甚至不需要看到他电脑的Excel界面——他把文件丢进data/目录,然后让AI直接干活就行。

5.2 顺手解决的Excel疑难杂症:公式下拉失效和Ctrl+V失效

在测试过程中,我还碰到过两个与MCP无关但一直困扰很多人的经典问题。

第一个是公式下拉失效,往往是因为Excel的自动计算被关闭,或者在某个区域存在合并单元格干扰了填充逻辑。另一个是Ctrl+V粘贴失效,常见原因是Excel进程残留、剪贴板被占用,或者某个后台插件拦截了剪贴板消息。遇到这种情况,我会先把所有EXCEL.EXE进程杀掉再重开,清掉剪贴板历史,如果还不行就再检查是否有加载项在搞鬼。

比起在界面里折腾,我现在更常用的解法是:直接让MCP Server的AI替我把整列公式写进对应区域。比如用户说“把F列从第2行到第100行都填上=D2*E2”,write_cell配合一个简单的循环工具就能快速完成,还能避开界面上的各种诡异故障。这不是说所有Excel界面问题都需要用AI解决,但它提供了一个完全不依赖Excel进程的可选路径。

5.3 一次完整的人机协作操作回放

为了让整个流程更直观,我给你回放一次我实际测试的完整操作。

用户对AI说:“统计2024年销售明细里,华东区每个省份的订单总金额,把结果写到名为‘汇总’的工作表A1单元格附近。”

AI在MCP工具列表里做了这样一串调用:

步骤工具参数结果
1list_sheetsfile_path=/data/sales_2024.xlsx返回“销售明细”、“客户基础信息”等sheet列表
2read_sheetsheet_name=销售明细, max_rows=20AI确认列名:省份、金额、备注
3filter_rowscolumn=省份, keyword=华东筛选出华东区所有行
4sum_by_keywordcolumn=省份, keyword=江苏, sum_column=金额返回金额总和
5sum_by_keyword同上,关键字换成浙江返回金额总和
6save_summary按省份分组,汇总金额,输出到“汇总”sheet生成汇总表

整个过程没有任何人写一行Python代码,AI根据我的自然语言描述,把需求拆解成了一个个原子工具的调用链。这种体验和之前写死脚本完全不同:如果哪天需求变成“统计华南区的城市订单数”,改一下自然语言即可,MCP工具本身不需要改动。

6. 进阶思路:从数据库导入到跨工具MCP编排

6.1 把Excel数据接进数据库

Excel处理往往只是“中转”,最终数据还得落到数据库里。这个需求也可以做成MCP工具,以SQLite为例:

import sqlite3 def excel_to_sqlite(file_path: str, sheet_name: str, db_path: str, table_name: str) -> dict: df = pd.read_excel(file_path, sheet_name=sheet_name) conn = sqlite3.connect(db_path) try: df.to_sql(table_name, conn, if_exists="replace", index=False) conn.commit() return {"status": "ok", "rows": len(df), "table": table_name} finally: conn.close()

AI拿到这个工具后,说一句“把这个月的销售明细导入到staging库的表sale_detail里”,它就能按参数完成导入。这里有两个提醒:一是大批量写入时建议分批,二是导出前先确认列名符合目标表结构,否则跑到一半报错回滚会很麻烦。

6.2 ArcGIS出图要插Excel表格?也可以顺着这条链路做

热搜里有一个很有意思的需求关键词:ArcGIS批量出图想插入Excel表格。很多GIS制图人员在批量出图时,希望在图廓里放一张来自Excel的统计表,但ArcGIS的布局视图里直接插入外部表格并不方便。

在MCP体系下,这个问题的解题思路变成了:用一个MCP工具把Excel统计表渲染成一张高清PNG图片(比如通过pandas转HTML再截图,或者直接用openpyxl+图片库转图),然后再用另一个MCP工具把图片送入GIS排版模板的动态文本框。本质上就是“表格转图片”这个动作标准化,AI就可以在批量出图的流程里自动完成表格插入。这种做法不绑定某个具体GIS版本,理论上只要支持图片锚定的布局都能用。

6.3 MCP的“万物连接”现状:Dify、设计稿、低代码平台

现在MCP已经不局限于“AI+Office”这个场景。像Dify这类低代码平台已经内置了对MCP工具节点的支持,浏览器自动化也有专门的MCP Server,设计稿工具Figma、蓝湖也有社区提供的MCP适配器,“Codex接入Figma MCP”这类操作我甚至看过不止一个教程。就连一些项目管理系统(比如你在网上搜得到的ruoyi-vue-pro相关功能合并方案),也在想办法把MCP作为外部工具入口。

这一轮生态快速扩张,给普通开发者的启发是:**MCP不是某个公司私有的东西,它是一套公共协议。**你今天写了一个Excel MCP Server,明天如果想让AI去操作数据库、调用浏览器、读取设计稿,思路完全一致——写独立的Server,注册工具,挂到同一个客户端下。工具可以彼此独立演进,但接入成本几乎为零。

6.4 调试器、事务系统与其他边界连接

更极客一点的玩法也有。现在已经有人把MCP接到x32dbg这类调试器上,也有人在做Cheat Engine桥接MCP的教程,还有一些事务系统、硬件系统通过MCP暴露状态接口给AI。这个方向本质上是在做“本地工具的标准化远程控制”,让AI Agent能够操作原本只有人类通过界面才能操作的对象。

我对这类偏门连接的态度是:MCP提供了一个结构化的协议框架,只要对方愿意实现Server端,任何工具理论上都能接入。但对个人项目来说,优先考虑“收益/复杂度”比——先把Excel、文件、数据库这类高频场景跑通,再考虑那些调试器级别的连接,避免掉进“万事通但一事无成”的陷阱。

做这套Excel MCP Server,我最大的感受是:MCP改变的不只是AI的“对话能力”,而是AI的“做事半径”。以前每个Excel需求都是独立的临时脚本,现在只要你把read、write、filter、sum这几个基础动作打磨干净,AI就能像拼积木一样组合出无数种用法。我现在临时接到“统计某几列关键词对应的总和”之类的需求,已经很少自己打开Excel了,把文件丢给MCP链路,AI跑一圈给出汇总结果比手工还快。

如果你也想做自己的第一个MCP,我建议别一上来就设计二十个工具。从read_sheet和write_cell这两个最朴素的功能开始,先验证配置、通信、备份这条链路通畅,再加统计、汇总、导出这些花活。权限、备份、报错信息这三样东西做得越细,后面维护越省心。等哪天你发现AI能通过你的工具把活干完而不是只给建议,你就知道这个项目真正成了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 15:10:30

模拟退火与粒子群算法在机械优化中的对比应用

1. 项目概述&#xff1a;当优化问题遇上智能算法在工程优化领域&#xff0c;我们常常会遇到各种带约束条件的非线性优化问题。这类问题往往目标函数复杂、约束条件多样&#xff0c;传统数学规划方法要么难以求解&#xff0c;要么计算成本过高。这时候&#xff0c;智能优化算法就…

作者头像 李华
网站建设 2026/10/14 15:09:58

Spring Aware机制深度解析:回调原理、执行顺序与自定义实现

几年前带过一个转岗过来的 Java 开发&#xff0c;他指着基础工程里一段 Spring 代码问&#xff1a;这个实现 ApplicationContextAware 的接口到底是干嘛的&#xff1f;我直接 Autowired 一个 ApplicationContext 不也一样吗&#xff1f;我当时愣了一下——不是因为他问得幼稚&a…

作者头像 李华
网站建设 2026/10/14 15:09:54

PyQtChart实时动态曲线绘制:从数据缓存到性能优化的完整实践

1. 核心思路与架构拆解很多人一提到“动态曲线”第一时间想到的是 matplotlib 里的plt.ion()加循环重绘&#xff0c;但在做桌面工具类的实时监控、数据采集、硬件波形显示时&#xff0c;我几乎不会用 matplotlib。原因很简单&#xff1a;matplotlib 重绘整个 Figure 的开销太大…

作者头像 李华
网站建设 2026/10/14 15:09:26

PCB收放板设备整机尺寸与厂房适配选型参考——从1700mm到17100mm布局对比

PCB厂房的空间规划直接影响设备选型。画册中设备整机尺寸跨度从1700mm到17100mm&#xff0c;不同工序段的设备占地面积差异显著。厂房空间有限时&#xff0c;设备尺寸和布局方式成为选型的关键约束。本文按设备尺寸分类&#xff0c;对比不同尺寸段的设备参数&#xff0c;供选型…

作者头像 李华
网站建设 2026/10/14 15:09:14

安卓设备通过S7协议采集西门子PLC全系列数据方案详解

做工业物联网这一行&#xff0c;最绕不开的就是和西门子PLC打交道。我最近半年都在折腾安卓设备直接走以太网通讯采集PLC数据的项目&#xff0c;期间加了几个同行群&#xff0c;发现一个特别共性的需求&#xff1a;大家都在找能兼容西门子全系PLC的安卓通讯方案——S7-300、S7-…

作者头像 李华