我在不可靠的移动数据连接上使用TCP,这可能会因干扰或信号强度可能出现的任何问题而丢弃数据包。
重要的是我使用的是Modbus TCP,而另一端的移动路由器将其转换为Modbus RTU(串行),以便与基于串行的设备(从设备)进行通信。
此外,每当向串行设备发送读取请求时,一旦发送响应,其内部指针就会递增到下一个数据块。串口设备不知道移动连接是否仍然正常;如果响应没有一直回到服务器,那么无论如何它都已经增加了它的内部指针。
换句话说,请采取以下方案:
在上面的场景中,您将看到步骤5中的问题导致错过整个数据块,因为串行设备不知道先前的读取操作实际上是失败的。它已经转移到下一个块!通常我会做的是检测这个问题并使用“请求先前数据块”操作来重新请求来自串行设备的先前丢失的数据块。
这是我的问题:我没有从TCP代码中获得任何异常或错误,即使我将所有内容都包含在SystemException try-catch块中并且我正在检查返回值。
我仔细查看了我的日志文件,发现请求和响应之间的时间约为1秒,但是在怀疑错过数据块时,时间间隔在2到3秒之间。这表明发生了发送,但没有收到任何数据,因此它再次尝试。但当然,当它再次尝试时,串行设备已经将其数据指针增加到下一组数据。
由于某种原因,串行设备收到了读取请求,但数据从未返回服务器。
我不是TCP / IP专家,所以有人知道会发生什么吗? TCP是否有可能在“引擎盖下”重新发送数据包而不会导致异常并且我不知道?
在我的代码中,我只是做这样的事情:
_log.Debug(string.Format("[{0}]: Sending sync response ({1}).",
this._IP.ToString(), CoreUtils.PayloadToString(write_data)));
tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);
int result = tcpSynCl.Receive(tcpSynClBuffer, 0,
tcpSynClBuffer.Length, SocketFlags.None);
byte function = tcpSynClBuffer[7];
byte[] data;
if (result == 0) throw SystemException("No data received");
// ... process log buffer ...
_log.Debug(string.Format("[{0}]: Got sync response ({1}).",
this._IP.ToString(), CoreUtils.PayloadToString(data)));
return data;
没有抛出异常,这表明发动机()和接收()之间发生了一些事情。两个调试日志条目之间的时间是所有其他条目的两倍。可能或不可能?
答案 0 :(得分:1)
首先:接收0字节并不意味着您没有收到任何内容。这意味着连接已关闭。
第二:由于Nagle算法,你很可能会同时收到两条消息。您需要浏览收到的字节并查看其中的消息。 TCP不是基于消息的,而是基于流的。
答案 1 :(得分:0)
TCP的重点是使流对应用程序透明。丢失的数据包由TCP而不是应用程序处理。如果TCP没有获得给定数据包的ACK,它将尝试重新发送数据包。它最终将停止发送任何其他数据包并继续重新发送丢失的数据包,直到它收到并确认或连接超时。
接收方类似。如果数据包丢失,TCP堆栈将不会向应用程序发送任何数据,直到它收到丢失的数据包。 TCP还保证数据包顺序。丢失的数据包将导致接收器停止,直到它丢失数据包或超时。
接收方将接收并缓冲丢弃数据包之后的一些数据包,并在收到丢失的数据包后“播放它们”。