==========TCP 编程的相关问题==========

2021-11-11 14:03:22 +08:00
 FreeWong
对方通过单片机使用 TCP 客户端的形式(短连接)与我写的服务端进行通讯
他们设计的协议是基于文本的,类似以下格式

@Start:A01:25.41,A02:36.1#

其中#号表示一条完整的可解析的数据的结尾,同时 TCP 客户端要求当服务器收到一条完整的数据后,要回复 @Received 用于表示接收到这条数据。
并且客户端会等待我的这个回复,才会断开 TCP 客户端一侧的连接,十几秒都没有收到则主动断开。(我们不考虑它主动断开的情况)
如果服务端没有回复,则到下一个通讯时间节点时,再次将前面没有收到回复的数据补发,然后再接着发送当前时间节点应该发送的。
像这样
@Start:A01:25.41,A02:36.1#@Start:A01:26.18,A02:38.2#

很多编程语言提供类似 ReadTo() 方法,意思是这个方法不返回,一直读到指定的字符时返回,所以 ReadTo("#") 就会返回一条完整的数据。 但是由于存在补发数据的情况,所以得循环调用这个方法像这样
for{
string 完整的数据 =ReadTo("#")
开始处理完整的数据的函数(完整的数据)
}

你们发现没有,由于我根本不知道客户端会有多少个完整的数据的指示符,所以我的服务端必须要循环调用 ReadTo("#") 并且我根本不知道什么时候该退出循环。
也就无法向 TCP 客户端发送 @Received 让来客户端断开连接。
现在就变成了,我根本不知道何时结束循环也就无法发送 @Received,而客户端也在等待我给它指示断开的指令,这样面临一个类似“死锁”状态。

这里只讨论 ReadTo("#") 这个方法

所以我的看法就,TCP 客户端应该将多条补发数据的格式修改为

@Start:A01:25.41,A02:36.1;@Start:A01:26.18,A02:38.2#

将中间的 #号修改为 ; 号,这样的话, 我都不需要使用循环来读。
请问,我的想法有没有考虑不周全的地方?感谢大家指正。
1592 次点击
所在节点    问与答
24 条回复
Sricecake
2021-11-15 13:14:25 +08:00
问题点在于 TCP 是流式的,你却把它当 HTTP 用。
正常应该是每条数据应该有个 ID 你收到一个# 就回一条 Received(ID)
你只负责一直循环 ReadTo 处理完一条就回一条 Received
客户端判断所有消息都 Received 了再断开连接就行。
FreeWong
2021-11-18 11:02:36 +08:00
@Sricecake 客户端的现在的错误逻辑,就是我只要回一条接收到的消息, 它就断开了。。如果客户端自己还有很多数据要发,它照样断 。。。这本来就是在一个错误的逻辑上修补。
客户端是硬件厂商做的,我无法修改
Sricecake
2021-11-19 19:22:40 +08:00
按 #19 的说法 方法可行的话让供应商下个版本修改,按正确逻辑改了就可以了吧。
FreeWong
2021-11-23 08:50:00 +08:00
我的问题是,我的方法是否可行,有没有逻辑上说不通的地方。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/814687

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX