
半夜接到现场电话这种事搞工业自动化的应该都懂。电话那头说上位机连不上PLC了S7通信协议握手失败Snap7报了一串莫名其妙的错误码。我远程上去一看IP能ping通、TCP 102端口也开着抓包发现COTP连接请求发过去了对面却回了拒绝。折腾了快半小时最后发现就是TSAP配置的问题——填错了一个看似人畜无害的参数。TSAP这东西在西门子S7通信协议里属于那种“不报错就永远想不起来报错了又让人满头问号”的配置项。尤其当你用第三方库Snap7、HslCommunication、Node-RED的s7节点这类做上位机或网关时它几乎是绕不开的门槛。TIA Portal里S7-1200/1500的TSAP被隐藏得干干净净导致很多只接触过博途的人压根不知道有这东西可一旦切换到S7-300/400或者要用CP343-1这类通信处理器TSAP就成了决定成败的关键。这篇文章我打算把TSAP从原理到实操完整捋一遍它到底是谁、各系列PLC的默认值是什么、什么时候需要自定义、怎么用Wireshark验证自己填的对不对。适合正在做上位机、MES采集、物联网网关对接的工程师也适合刚被TSAP折磨过的新手。1. TSAP是什么S7通信里那个经常被跳过却决定成败的“传输服务访问点”1.1 从协议栈看TSAP的位置先纠正一个常见认知S7通信并不是直接用TCP/IP就能完成的。完整的S7 over Ethernet协议栈长这样应用层S7COMM就是我们在Wireshark里看到的s7comm协议包传输层COTP / TPKT也就是ISO-on-TCP对应RFC 1006规范网络层TCP/IP固定用TCP 102端口TSAP就是COTP层里的一个字段全称Transport Service Access Point传输服务访问点。它的作用区间在TCP连接建立之后、S7COMM握手开始之前。你可以把IP理解成小区地址TCP 102端口理解成单元楼大门而TSAP就是楼里具体哪一户。同一个IP、同一个端口上可能跑着多个S7服务靠TSAP来区分你究竟要访问哪个服务。这个类比很重要因为后面讲到的“为什么同一个PLC有不同的TSAP”“为什么有时候要改TSAP”本质上都是在回答“你要敲哪一户的门”。1.2 为什么很多人没听过TSAPTIA Portal针对S7-1200/1500做了一件“贴心”的事在连接属性里不显示TSAP后台直接用一个固定值替用户处理了。结果是大量只玩过S7-1200/1500的工程师根本不知道协议里还有这层东西。直到某天他需要用第三方库去采集S7-300数据翻文档看到TSAP参数一脸茫然。更麻烦的是网上关于TSAP的说法还特别乱——有人写03.01有人写01.00有人写02.01甚至同一台S7-300在不同教程里给出的TSAP都不一样。这不是谁记错了。真实情况是一台PLC可能有多个S7服务接口CPU集成PN口、CP343-1通信卡、经网关转发各自使用的TSAP确实可能不同。所以理解TSAP的配置逻辑比死记一个默认值重要得多。1.3 TSAP在连接建立过程中的角色在ISO-on-TCP的握手流程里发起方会发送一个COTP Connection RequestCR报文里面携带两个关键字段源TSAPSRC-TSAP和目标TSAPDST-TSAP。服务端收到CR后如果认为TSAP合法并且自己有对应的服务在监听就会回COTP Connection ConfirmCC报文S7COMM握手才正式开始。如果TSAP不对服务端可能直接不回包或者回一个带拒绝原因的CC报文表现为“TCP能连上但S7握手失败”。这里有一个很经典的排错分界点如果抓包根本看不到CR报文说明问题在IP路由、防火墙或端口上如果看到CR但CC被拒绝大概率就是TSAP的问题。把这条分界线记牢能帮你省掉大半晚上的排查时间。2. 各系列PLC的TSAP默认值速查从S7-200到S7-1500到底该填什么2.1 一张能直接抄作业的速查表先说结论下面这张表是我在实际项目和社区交流里反复验证过的经验值。考虑到不同固件和通信接口的差异我把它定位为“多数项目可用的起点值”不是绝对真理。PLC系列常见默认TSAP远程/目标侧说明S7-20003.01老一代S7-200通过以太网模块或PC Access访问时常见S7-200 Smart02.01标准以太网口连接时常见也有项目用03.01S7-300CPU集成PN口03.01部分固件/接口存在01.00或02.01的情况S7-400CPU集成PN口03.01同样存在因接口而异的可能S7-1200/150003.01TIA中隐藏底层实际使用第三方库常见0x0301CP343-1/CP443-1通信卡随CP槽位变化常见04.01取决于通信处理器所在槽位把这个表和实际项目对照时你会发现一个规律S7-1200/1500/200的TSAP基本是固定的而S7-300/400以及带CP卡的场景TSAP才会真正变成“变量”。2.2 S7-300/400的TSAP为什么和机架槽位有关S7-300/400的TSAP在STEP7/TIA的S7连接组态里通常是根据站点的机架号Rack和槽号Slot计算出来的。CPU所在槽位不同、通信处理器所在槽位不同生成出来的TSAP就不一样。用CP343-1举个例子CPU在机架0槽2CP343-1插在槽4这时候经CP访问CPU时目标TSAP往往就不是CPU集成接口的那个默认值了而会随CP槽位变化。很多人在这一步翻车就是拿S7-1200的经验硬套S7-300CP场景以为TSAP永远都是03.01。所以做S7-300/400通信时我的习惯是先到TIA或STEP7的NetPro里看一眼连接的TSAP属性再写到第三方库里。虽然麻烦一点但比靠猜靠谱得多。2.3 第三方库自带的默认值逻辑不少第三方库为了降低使用门槛不直接让你填TSAP而是填机架号和槽号库内部自动计算TSAP。比如HslCommunication的SiemensS7Net构造时区分了S300、S1200、S1500等型号内部对每个型号都有默认的Rack和Slot。S7-1200默认Slot1S7-300默认Slot2这些默认值跟硬件实际槽位一致时基本开箱即用。这种设计很友好但也埋了一个坑当你换了CPU型号或改了硬件槽位忘了同步修改Rack/Slot参数库内部算出来的TSAP就会偏离实际导致连接到错误的服务。记住一个原则无论哪种库凡是看到Rack和Slot参数它们最终的归宿都是TSAP。3. 自定义修改TSAP的实操路径从TIA组态到第三方库传参3.1 TIA Portal和STEP7里怎么看TSAPS7-1200/1500在TIA里看不到TSAP因为CPU集成PN接口的S7服务是固定映射的不允许用户干预。但如果组态的是S7-300/400的S7连接连接属性对话框里能看到TSAP相关参数。具体路径大概是先打开设备和网络视图建立S7连接后在连接表里双击对应连接查看属性的“地址详细信息”或类似页签。那里会列出本地端点和伙伴端的TSAP。还有一种更直接的办法在硬件组态里选中CPU或CP查看其属性的“接口”信息。不同博途版本界面差异不小我遇到过好几个项目版本不一样TSAP藏在的位置也不同。如果实在找不到直接跳到下一章用Wireshark抓包看反而更快。3.2 第三方库手动传TSAP以Snap7和HSL为例用第三方库时TSAP通常有两种传法字符串形式和16位数值形式。字符串形式的“03.01”其实就是两个字节0x03和0x01的点分写法组合成16位数值就是0x0301。Snap7的C接口里SetConnectionParams函数接受本地TSAP和远程TSAP两个参数。以连接S7-1200为例TS7Client client; client.SetConnectionParams(192.168.0.10, 0x0100, 0x0301); client.Connect();这里的0x0100是本地TSAP也就是上位机这一侧的服务访问点0x0301是远程TSAP是PLC那一侧的S7服务接口。很多初学Snap7的人只改IP忘了把远程TSAP从示例值改成自己设备对应的值结果就是连不上。Python版Snap7的写法类似import snap7 client snap7.client.Client() client.set_connection_params(192.168.0.10, local_tsap0x0100, remote_tsap0x0301) client.connect()HslCommunication则提供了更友好的方式直接传入机型、IP和可选的机架槽号SiemensS7Net s7 new SiemensS7Net(SiemensPLCS.S1200, 192.168.0.10); s7.Rack 0; s7.Slot 1;如果想把HSL切到手动模式直接指定TSAP字节也不需要慌HSL内部其实还是把Rack、Slot换算成TSAP去握手理解这一点就知道怎么调。3.3 本地TSAP和远程TSAP到底怎么区分本地TSAP和远程TSAP的分工很多人第一次接触就懵。我打个比方本地TSAP是你的工牌远程TSAP是你要拜访部门的门禁号。COTP连接请求里两个字段都要填但实际决定能不能进门的是远程TSAP是否匹配PLC上的S7服务。Snap7的本地TSAP用0x0100或者0x0301的都有多数情况下PLC不校验源TSAP所以本地TSAP即使填得“不太标准”连接也可能成功。但对S7-300这类会严格核对TSAP的设备远程TSAP错一个数字都进不去。这就是为什么排查TSAP问题时优先确认远程TSAP本地TSAP只要不是明显非法值一般不用动。3.4 自定义修改TSAP的真实场景哪些情况需要手动修改TSAP而不是用默认值我整理了三个高频场景CP通信处理器转发CPU和CP的槽位组合导致TSAP不再是03.01一台PLC上存在多个S7服务比如同时有标准S7通信和S7 OPC UA服务需要指定到具体服务冗余系统或软冗余场景S7-400H等冗余PLC在切换机架时TSAP可能对应不同子机架的组态遇到这些场景唯一正确的做法就是回到组态或抓包拿到实际TSAP再改。别凭记忆硬填。4. 抓包验证TSAP与其猜不如亲眼在Wireshark里看4.1 抓包的具体操作抓包验证TSAP是效率最高的排错手段比翻文档和问群友都快。打开Wireshark选择PLC所在网卡的接口先不急着过滤直接在上位机上发起一次S7连接尝试。然后停止抓包在过滤器里输入tcp.port 102如果连接请求还没来得及发就被本地拦截可能需要换个网卡或者检查防火墙。过滤器定到TCP 102端口后重点找COTP层的Connection Request报文。4.2 怎么看COTP连接请求里的TSAP找到COTP Connection Request通常标记为CR后展开COTP层。里面能看到类似这样的信息COTP Header LengthPDU Type0xE0表示CRDestination TSAP目标TSAPSource TSAP源TSAP比如目标TSAP显示为03 01对应字符串就是“03.01”十六进制就是0x0301。把这个值和你的配置比一下立刻就能看出来填没填对。有一点需要注意不同Wireshark版本对TSAP字段的解析显示方式可能不一样有些直接显示点分十进制有些显示原始十六进制字节。不过你只要认准“Destination TSAP”旁边那两个字节再和配置对照就行。4.3 区分TSAP错误和其他故障的经验表抓包之后根据报文的出现情况可以快速定位问题归属。这张表我贴过很多次每次都帮人省时间抓包现象问题归属处理方向完全没有TCP SYN或SYN-ACKIP地址、路由、网段、防火墙检查网络连通性放行TCP 102TCP三次握手成功但没有COTP CR对端没有S7服务在监听或端口被中间设备拦截确认PLC侧S7服务使能检查交换机ACL有CR但无CC或CC带拒绝原因TSAP不匹配或连接资源被占满核对TSAP检查PLC连接资源CR/CC都正常但S7COMM层报错权限、连接数、Block读取权限等问题检查S7连接机制和DB访问权限有了这张表就算TSAP一时半会没搞定你至少知道该往哪个方向查不会在黑夜里乱撞。4.4 抓包中的一个典型对照案例我之前遇到过一台S7-300上位机用Snap7连接报错一直说是TCP连接问题。抓包后TCP三次握手正常COTP CR也发出去了但PLC那边就是不回CC。后来我把CR报文里的Destination TSAP展开一看PLC期望的是01 02对应“01.02”而我代码里填的远程TSAP是0x0301。改成0x0102后连接秒开。这件事给我的教训是TCP层能通不代表S7层能通S7层能通不代表TSAP就对。每一层都有各自的“门禁”TSAP就是其中最容易出问题的那道。5. 我踩过的TSAP坑三条排错记录和一个自查清单5.1 坑一S7-1200不严格校验TSAP让我误以为配置全对S7-1200/1500在TSAP校验上比较宽松有时候你填一个“差不多”的值也能连上。我曾在开发环境用S7-1200测试程序TSAP随便填了0x0100结果跑通了心里还挺美。到现场换成一台S7-300同样的代码怎么都连不上。后来才明白S7-300对TSAP的校验远比S7-1200严格。这也解释了为啥网上很多人抱怨“同一个程序在1200上好使到300就不行”。这个坑的教训是开发测试用的PLC型号和现场实际用的PLC型号不一致时一定要重新审视所有和机型相关的参数TSAP首当其冲。5.2 坑二一个IP上挂了多个设备TSAP指错了对象某些大型设备里一个IP背后可能不只一个S7服务。比如一台设备既有CPU集成的PN口又有额外的CP343-1插在别的槽位二者各自监听不同的TSAP。如果上位机只管填默认的03.01有可能连上了CPU却访问不到你想读的某个通信数据区。这个坑特别隐蔽因为“连上了”不等于“连对了”。你的程序没报错但读回来的数据永远是空的或不对的排查半天才发现原来连的是另一个服务。遇到这种场景别嫌麻烦用TIA看一眼连接属性或者抓包确认正在和目标设备通信的实际TSAP是什么。5.3 坑三字符串格式和十六进制格式的换算搞混第三方库的TSAP参数有的是字符串“03.01”有的是十六进制0x0301有的甚至让你直接传两个字节。如果不小心把“03.01”这个字符串当成0x0301传进去等于把两个字节倒置或者多了一个分隔符连接必然失败。我见过一个项目同事把Snap7远程TSAP写成0x0103他想表达“01.03”结果连S7-300怎么都连不上。其实“01.03”对应的十六进制是0x0103没错但问题是目标PLC实际用的是“01.02”和格式无关纯粹是值不对。所以我的建议是无论什么库先明确参数的类型是字符串还是16位整数再看看点分十进制和十六进制之间的对应关系最后确认值本身匹配PLC侧的TSAP。5.4 TSAP排查自查清单最后整理一份排查清单下次再遇到连不上照着过一遍确认IP、子网、网关没问题能ping通确认TCP 102端口可达可用telnet或nc测抓包看COTP CR是否发出有没有CC返回若有CR无CC展开Destination TSAP和PLC组态里的TSAP比对确认库参数类型是字符串还是十六进制别搞混格式确认现场PLC型号和开发时一致避免S7-1200的宽松规则掩盖问题若涉及CP或冗余回到TIA/NetPro查实际TSAP若一切正常仍连不上考虑PLC连接资源是否被占满这套清单我随身带着已经帮不止一个现场解决过“玄学”断连问题。用TSAP配置这件事说到底就一句话不要跟PLC讲道理它只认自己组态里的那个值。你以为填对了不算数Wireshark里的字节才算数。若再遇到连接问题先抓包看CR报文再动手改参数比反复试错省太多时间。最后分享一个小技巧把常见PLC型号的TSAP记录到一张自己的笔记里下次到现场直接从记录里取候选值再配合抓包确认基本十分钟之内能把TSAP问题定案。