您好,欢迎访问飞畅科技官网!
服务热线:+086 0571-87007055/56/57 EN
飞畅科技工业通信技术中心

光通信与工业互联网方案专家

EXPERT IN OPTICAL COMMUNICATION & INDUSTRIAL INTERNET SOLUTIONS

联系我们CONTACT US

全国咨询热线

0571-87007055/56/57/75

市场部直线电话:0571-87007140

手机:15306818230(微信)

QQ :2355416925

定制设计:18072828031(微信)

或给我们留言

在线留言

为什么发了FIN还能收到数据?TCP半关闭与串口回传科普

浏览次数:飞畅科技原创作者:飞畅科技技术团队

FIBERIOT / 基础知识

上位机已经发出FIN,为什么抓包里还有对方回传的数据?这不一定是故障。TCP连接里的两个发送方向可以分别结束:我不再发送,不等于你也不能发送。理解这件事,要把网络协议的结束标记、程序读取的结果,以及串口设备真正完成的动作分开。

TCP连接两个方向分别结束,甲停止发送后仍可接收乙的回复
图1:双向字节流与半关闭概念;AI辅助原创绘制,非物理接线图或具体型号承诺。

01一条连接里,有两个各自前进的字节流

可以把TCP连接想成两个人通电话:一方说“我的话讲完了”,另一方仍可能需要回答。不过电话只是类比,TCP真正传送的是有顺序的字节流,不理解文字、命令或机器动作。两个方向分别管理自己的数据和结束状态,不能把一方的结束当成双方同时消失。

这里的“双向”是在说传输层的两个字节流,不是在判断交换机端口的全双工、半双工设置。物理接口怎样收发、TCP怎样管理连接、应用怎样识别一条完整消息,是不同层次的问题。名字相近,也不能拿某一层的状态代替另一层的结论。

因此,看到连接建立过,并不意味着它会永远保持;看到发送方向结束,也不意味着接收方向立即失效。工程人员应先问清楚:谁结束了哪个方向,什么程序作出了决定,还有哪些数据尚未交给应用。

02FIN说的是“这个方向后面没有新数据了”

FIN是TCP报文头里的一个控制标志,不是串口命令中的结束字符。正常关闭时,它在本方向的数据序列中表示结束位置。接收端要按顺序处理此前的数据,不能因为先观察到一个带FIN的报文,就跳过前面尚未补齐的字节。

对端确认FIN,只能说明TCP层按其规则确认了这个结束位置。它不等于控制器已经执行命令,也不等于串口发送器已经把最后一个字符送出。网络确认与业务成功之间,还隔着缓冲、程序处理和现场设备自己的响应。

FIN也不是一条要求对方马上断电、停止串口或删除缓存的指令。设备收到它之后采取什么应用策略,取决于程序与固件实现。本文解释正常TCP机制,不据此给任何一款串口服务器承诺固定的关闭动作。

03发送结束后,对方为什么还能回话

假设程序甲把请求发给程序乙,随后只结束甲的发送方向。乙可以先确认甲的结束,再通过仍然开放的反方向发送剩余回复,等自己也没有新数据时再结束发送。甲在等待期间继续读取,便可能收到这些回复,这正是半关闭能够发挥作用的情形。

图中的请求与回复只是说明方向关系,不是建议把每条工业命令后面都加一次关闭。有些应用约定以流结束作为输入完成的信号,有些则使用长度、分隔符或协议自身字段,还有很多工业连接需要长期保持。必须先遵守实际应用协议。

TCP是字节流,报文数量也不是固定的。确认可以与数据合并,网络还可能重传或重新分段,所以不能机械地数“四个包”来判断一次关闭是否合格。更可靠的方法,是看方向、顺序和各自发送结束的位置。

甲发送FIN后乙仍可发送回复,再结束自己的发送方向
图2:一种正常关闭时序示意,确认可能与数据合并,不代表固定报文数量或实测时延。

04程序读到零字节,与暂时没数据不是一回事

对常见的面向连接接收接口,在提供正常的非零接收缓冲区时,正常读到零字节通常表示对方的有序结束已经到达应用可观察的位置。它与“这一刻还没有数据可读”不同。非阻塞暂不可读、等待超时和连接复位,应按各自返回值或错误信息分别处理。

如果接收缓冲里还有先前到达、尚未被程序取走的字节,程序可能先一次或多次读到这些字节,之后才读到结束。收到FIN,并不会把本来可交付的数据自动变成空白。图中的队列是概念模型,不代表某操作系统的实际内存排布。

一次读取也不保证刚好对应一条业务回复。程序仍要按应用协议拼出完整内容,核对长度、序号或状态字段。不能把“本次读取成功”直接写成“整条回复已经收齐”,更不能把EOF当成所有协议通用的成功标识。

05只关发送,与释放整个接口要分清

一些系统提供只关闭发送方向的接口,例如Windows套接字的shutdown配合SD_SEND。它与释放套接字句柄的closesocket有不同职责。这里举名字,是帮助读者对照开发文档,不提供一套适用于所有平台的固定程序步骤。

实际关闭行为还受平台、选项、尚未读出的数据及错误情况影响。正常有序结束和RST复位也要分开:前者表达按序结束,后者表示连接被复位。看到RST时,应结合设备日志和程序错误调查,不能把它涂改成“正常挥手”。

半关闭也不同于半开连接。前者可以是双方状态一致、某个方向正常结束的阶段;后者通常涉及一端已失去连接状态而另一端尚未察觉。不要仅凭界面写了“连接异常”,就把所有这些情况都归到同一种故障里。

接收缓冲中未读数据先交给应用,排空后才报告正常流结束
图3:有序结束的接收概念模型,非操作系统内存结构;错误、复位与超时须分别处理。

06串口服务器把问题带到了另一条链路

飞畅官网的单路三合一串口服务器资料列有TCP工作模式,这是真实的产品背景。但支持TCP,不自动证明某型号允许用户控制半关闭、提供某种缓冲排空接口,或采用本文图示的固件策略。这些能力必须查具体型号、版本和说明。

网络字节进入串口服务器后,可能还要等待缓存处理、串口发送以及现场设备回复。上位机停止发送的时刻,与现场仪表完成动作的时刻,并没有天然的一一对应关系。即使网络收到了确认,串口业务也可能还在继续。

反方向同样如此:仪表已经回了一部分数据,网关是否继续转发、保留还是丢弃后续内容,要看它对当前会话的实际处理方式。测试时应记录串口侧与网络侧两个观察点,不用某一端的单张截图替代完整过程。

07怎样用证据判断,而不是靠重复重连

排查可以从一条受控请求开始,记录发送内容、预期回复、双方日志和抓包时间。先确认哪一端发送FIN或RST,再核对接收程序读到了多少字节、怎样解释结束,以及串口侧何时收到和发出数据。需要测试时,应在批准的测试环境或维护窗口进行。

例如,读操作只返回了半条回复时,应保存已经取得的原始字节,再按协议继续等待或报告不完整,不能把后续数据换到一条新连接里随意拼接。连接是传送上下文,业务请求也需要自己的对应关系;把两者分别记录,复盘时才知道某段回复属于哪次请求。

还应事先定义等待期限与业务成功条件,避免对方一直不结束时无限等候。超时不代表命令一定没有执行,直接重连重发可能让写入或动作重复发生。是否允许重试,应由业务协议、幂等设计和设备反馈决定,不由TCP连接状态单独决定。

记住三句话:FIN结束一个发送方向;可继续接收不等于必须无限等待;传输层完成不等于设备业务完成。把这三个边界讲清楚,就能更准确地读抓包、和软件人员沟通,并为串口联网项目提出可验证的验收条件。

资料依据

IETF RFC 9293第3.6节核对关闭与半关闭语义;Microsoft shutdown文档、有序关闭与套接字释放说明及recv文档用于区分平台接口和返回结果。产品背景:飞畅单路三合一串口服务器。通用协议与平台文档不证明该型号具备全部示例行为。

现场常见问题

FIN是否会同时关闭两个发送方向?

不会。正常TCP关闭按方向进行,一端结束发送后,反方向仍可能回传数据。应用与固件可以另有策略,需查实际实现。

收到FIN,就可以认为回复已经读完吗?

不能。先前到达的字节可能仍在接收缓冲中,应用通常先读取这些内容,再观察到正常流结束;业务完整性仍按应用协议判断。

串口服务器支持TCP,就保证支持半关闭回传吗?

不保证。要核实具体型号与固件如何处理会话关闭、串口缓存和后续回复,并通过受控场景测试,不能仅凭TCP工作模式推断。

适用边界与延伸阅读

通用TCP关闭与接收缓冲示意,非实测、操作系统内存结构或具体串口服务器固件保证。

串口服务器为什么会拆包和粘包:从UART字节到TCP流的完整原理;工业网络偶发卡顿:TCP怎样确认收齐数据,又为什么要重传