我有一个TCPClient,它创建了一个我在DataAvailable时读取的流。
每20秒!DataAvailable我用一条ACK消息ping套接字以防止流关闭。
但我似乎得到的结果好坏参半。似乎每隔一次我打开流(基本上重启我的服务)我就会出现传输错误。
这是我的Connect功能的缩短版本:
client = new StreamClient();
client.Connect(new IPEndPoint(clientAddress, senderPort));
stream = client.GetStream();
bool status = SendMessage(seq, sync, MessageTypes.Init);
SendMessage函数执行:
if (stream == null) return false;
stream.Write(TransmitBuffer, 0, TransmitMessageLength);
我的关闭功能确实:
if (stream != null)
{
SendMessage(seq, sync, MessageTypes.Finish);
stream.Close();
}
stream = null;
client.Close();
client = null;
由于套接字的性质,预计SendMessage调用偶尔会失败。
但有时候,一旦我连接,一切运行良好,没有失败的消息。但有时候ACK会失败。当ACK失败时,我调用Close,这将强制连接并验证套接字的另一端是否打开。如果失败那么我知道结束了。但有时候这个呼叫不会失败,然后20秒后ACK就会失败。
任何人都可以就这可能发生的原因向我发表意见吗?等待20秒太长了吗?我没有正确地关闭插座的末端吗?
我正在与之抗争的具体错误信息是:
Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.
它发生在stream.Write(TransmitBuffer, 0, TransmitMessageLength);
答案 0 :(得分:1)
通常,将协议置于TCP之上是一个很大的错误。它只能使连接 less 可靠。 TCP已经非常有力地保证从一台机器发送的数据将由网络上的另一台机器接收。只有非常严重的外部环境才能使失败。设备断电或计划外重启等事情。
除非其中一台机器故意关闭套接字,否则不的连接应该被破坏。当然,这应该以可预测的方式进行。事务的逻辑结束或计算机正在注销的显式消息。
除了“保持流关闭”之外,您没有动机将此“ACK协议”添加到连接逻辑中。我认为你在这里看到的是它只是不起作用,它实际上并没有阻止流关闭。所以它仍然像你在添加协议层之前那样出错,你仍然会意外地“已建立的连接被中止”例外。
您如何使 less 可靠的示例是您添加的20秒超时检查。 TCP不使用20秒超时。它使用指数退避算法来检查超时。通常它至少在45秒后才会放弃。因此,您将在 TCP之前声明连接死。
很难就如何向前推进提出建议。但显然不是通过添加协议,你尝试了它并且它不起作用。您必须找出连接意外断开的原因。不幸的是,这确实需要合作,您必须深入了解机器和服务器之间的网络设备和软件。有些人期望问题位于电线的另一端,因为那是最难诊断的问题。让网站的网络管理员参与您的问题是重要的第一步。
答案 1 :(得分:1)
我在你的实现中看到的主要内容是,我看起来你将Stream视为连接,而事实并非如此。您对Stream实例的检查应该是对TcpClient实例的检查。我不确定这是否是你问题的根源,但它对我来说肯定很奇怪。
而不是:
stream = client.GetStream();
if (stream != null)
{
SendMessage(seq, sync, MessageTypes.Finish);
stream.Close();
}
stream = null;
我通常会做更像这样的事情:
if (client != null)
{
if (client.Connected)
{
client.GetStream().Close();
}
client.Close();
client = null;
}
您应该在使用流之前检查TcpClient.Connected,而不是流本身 我要提到的另一件事是确保始终使用异步方法与TcpClient连接,读取和写入。同步的更容易,但我的经验是依靠它们会让你陷入困境。
答案 2 :(得分:1)
在开发network communication library时遇到了类似的问题。我们发现最可靠的解决方案只是发送一些空数据(即保持活跃),而不是使用ACK。在这种情况下,字节[1]的值为零。这将导致:
这些结果中的任何一个都确保了连接始终处于可用状态。
答案 3 :(得分:1)
为什么要发送ACK?你应该发送SYN。
你不应该发送ACK,SYN,RST或设置任何其他标志。你正在涉足TCP内部。你正在创建应用程序级协议,keep-alive是其中的一部分,因为,即使有http://msdn.microsoft.com/en-us/library/windows/desktop/ee470551%28v=vs.85%29.aspx连接也会打开,直到你关闭它。