我创建了一个到PLC的套接字连接:
IPEndPoint endPoint = new IPEndPoint(plcAddress, PORT);
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_socket.Connect(endPoint);
m_stream = new NetworkStream(m_socket);
m_writer = new StreamWriter(m_stream);
m_reader = new StreamReader(m_stream);
当我关闭程序或用户点击退出时,我会调用此代码:
if (m_reader != null) m_reader.Close();
if (m_writer != null) m_writer.Close();
if (m_stream != null) m_stream.Close();
if (m_socket != null)
{
m_socket.Shutdown(SocketShutdown.Both);
m_socket.Disconnect(false);
m_socket.Close();
m_socket.Dispose();
m_socket = null;
}
但PLC没有意识到连接已关闭。我无法更改PLC上的任何代码。
但是当我在连接处于活动状态时停止VisualStudio调试器(Shift + F5)时,它会正确关闭。什么是VisualStudio以不同的方式做什么?
修改:
当我通过Shift + F5
停止程序时,这两行由wireshark捕获
编辑2:
我有一个读取数据的线程:
while (m_runListener)
{
int cnt = m_reader.Read(buffer, 0, 1024);
if (cnt > 0)
{
// handle data
}
}
当我关闭程序时,我无法在不调用Thread.Abort();
的情况下停止该程序
如果我删除阻止呼叫m_reader.Read(buffer, 0, 1024);
仅用于测试,则断开连接工作。
答案 0 :(得分:0)
我最近遇到了一个非常类似的问题,我也发现通过Visual Studio进行调试也使问题消失了。我相信这是因为Visual Studio中的调试器需要额外的时间来处理事务,加上断点显然会阻止您在结束代码中执行的代码执行。
我讨厌的工作是在一些结束代码之间调用Thread.Sleep(xxxx)
。我在Shutdown
和Disconnect
调用之后有一个允许这些进程完成。我尝试了不同的值,但我确定了100毫秒,因为这确保问题再也不会发生。
显然,更好的方法是看看你是否可以将这些调用放入异步方法中,并且只在第一次完成时调用下一个调用,但由于项目规模较小而没有使用它,我没有打扰会得到。
然而,我可能完全错了,这不是你所遇到的问题,它听起来与我几周前的问题非常相似。
答案 1 :(得分:0)
我终于在这里找到了解决问题的方法:
http://sysperf.yingyuhsieh.com/2007/08/force-tcp-closed-by-sending-rst-c.html
通常,TCP连接关闭如下:
FIN
发送到服务器,服务器以ACK
FIN
,客户端以ACK
在我的情况下,第二步失踪了。
我需要强制发送RST
数据包。这可以通过以下代码完成:
m_socket.Send(new byte[1]);
m_socket.Shutdown(SocketShutdown.Receive);