Nic*_*ick 4 .net c# sockets tcpclient
我正在编写一个小型(C#)客户端应用程序,该应用程序使用TCP / IP连接将数据发送到远程服务器。我正在使用标准的.Net TcpClient对象,并且由于我要定期向服务器提交数据包,因此希望从客户端打开连接。但是,服务器可能会关闭连接,在这种情况下,我需要在发送下一个数据包之前重新连接。
使用Wireshark,当服务器终止连接时,我只能看到以下对话框:
server >>> FIN, ACK
ACK <<< client
我所没有看到的是我的客户拥有自己的FIN响应,以完成连接关闭。结果是我的客户端程序仅在发送下一个数据包后才发现连接已断开。
有什么方法可以设置TcpClient或它的基础Socket以完成断开连接,并提供一些反馈,以便我的客户端代码在发送下一个数据包之前知道重新连接?
为了回应以下评论而添加:我的发送代码非常简单-维护TcpClient和NetworkStream成员变量的对象具有一个成员函数,该成员函数包含(基本上)以下内容:
bool sent = false;
byte[] buffer = Encoding.UTF8.GetBytes(dataString);
while (!sent)
{
try
{
m_outStream.Write(buffer, 0, buffer.Length);
sent = true;
}
catch (Exception ex)
{
if (m_outStream != null) { m_outStream.Dispose(); }
m_client = new TcpClient(AddressFamily.InterNetwork);
m_client.Connect(ipAddress, ipPort);
m_outStream = m_client.GetStream();
}
}
Run Code Online (Sandbox Code Playgroud)
初始化了m_client和m_outStream以后,每次只需执行一次传递。然后,使用Wireshark,我可以看到服务器发送了带有标志的数据包,FIN, ACK客户端对此进行了响应ACK。
下次调用函数时,数据将通过发送出去PSH, ACK,服务器将以响应RST, ACK但不读取传入的数据。客户端不会引发异常。
然后,我第二次调用函数,并引发异常,导致重新启动连接。
通常,您应该能够Connected在TcpCient实例上使用该属性:
参见此处:http :
//msdn.microsoft.com/zh-cn/library/system.net.sockets.tcpclient.connected.aspx
然而:
因为Connected属性仅反映最近操作的连接状态,所以您应尝试发送或接收消息以确定当前状态。消息发送失败后,此属性不再返回true。请注意,此行为是设计使然。您不能可靠地测试连接状态,因为在测试和发送/接收之间的时间内,连接可能已经丢失。您的代码应假定套接字已连接,并且可以正常处理失败的传输。
请尝试以下操作以确保该Connected标志保存最新状态:
var tcpClient = new TcpClient ();
tcpClient.Connect();
var stream = tcpClient.GetStream();
// buffer size need to be > 0
int[] buffer = new int[1];
stream.Read(buffer, 0, 0);
if(!tcpClient.Connected)
// do something
Run Code Online (Sandbox Code Playgroud)
基于反编译,应该可以0从流中读取字节,至少.NET Framework TcpClient中没有检查阻止此操作。但是,从框架调用以实际从网络流读取的外部代码中可能并不大声。
一定要Dispose既TcpClient和Stream你做了之后,处分TcpClient不处置的Stream,所以你需要手动待办事项本,之后,将所有资源都被释放了(GC后)。