C# 如何检查 TcpClient 连接是否已关闭?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1387459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to check if TcpClient Connection is closed?
提问by Superdumbell
I'm playing around with the TcpClient and I'm trying to figure out how to make the Connected property say false when a connection is dropped.
我正在尝试使用 TcpClient 并试图弄清楚如何在连接断开时使 Connected 属性显示为 false。
I tried doing
我试着做
NetworkStream ns = client.GetStream();
ns.Write(new byte[1], 0, 0);
But it still will not show me if the TcpClient is disconnected. How would you go about this using a TcpClient?
但是如果 TcpClient 断开连接,它仍然不会显示我。你会如何使用 TcpClient 来解决这个问题?
回答by Kepboy
As far as I know/remember there is no way to test if a socket is connected other than reading or writing to it.
据我所知/记得,除了读取或写入套接字之外,没有其他方法可以测试套接字是否已连接。
I haven't used the TcpClient at all but the Socket class will return 0 from a call to Read if the remote end has been shutdown gracefully. If the remote end doesn't shutdown gracefully [I think] you get a timeout exception, can't remember the type sorry.
我根本没有使用 TcpClient 但如果远程端正常关闭,Socket 类将从对 Read 的调用返回 0。如果远程端没有正常关闭[我认为]你会得到一个超时异常,抱歉不记得类型。
Using code like 'if(socket.Connected) { socket.Write(...) }
creates a race condition. You're better off just calling socket.Write and handling the exceptions and/or disconnections.
使用像 ' 这样的代码if(socket.Connected) { socket.Write(...) }
会产生竞争条件。您最好只调用 socket.Write 并处理异常和/或断开连接。
回答by Akshay Vats
Try this, it works for me
试试这个,它对我有用
private void timer1_Tick(object sender, EventArgs e)
{
if (client.Client.Poll(0, SelectMode.SelectRead))
{
if (!client.Connected) sConnected = false;
else
{
byte[] b = new byte[1];
try
{
if (client.Client.Receive(b, SocketFlags.Peek) == 0)
{
// Client disconnected
sConnected = false;
}
}
catch { sConnected = false; }
}
}
if (!sConnected)
{
//--Basically what you want to do afterwards
timer1.Stop();
client.Close();
ReConnect();
}
}
i used Timer because, I wanted to check connection state at regular interval and not in a LOOP with Listening code [I felt it was slowing the sending-recieving process]
我使用 Timer 是因为,我想定期检查连接状态,而不是在带有侦听代码的 LOOP 中 [我觉得它会减慢发送-接收过程]
回答by uriel
I wouldn't recommend you to try write just for testing the socket. And don't relay on .NET's Connected property either.
我不建议您尝试编写仅用于测试套接字。也不要依赖 .NET 的 Connected 属性。
If you want to know if the remote end point is still active, you can use TcpConnectionInformation:
如果您想知道远程端点是否仍处于活动状态,可以使用 TcpConnectionInformation:
TcpClient client = new TcpClient(host, port);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();
if (tcpConnections != null && tcpConnections.Length > 0)
{
TcpState stateOfConnection = tcpConnections.First().State;
if (stateOfConnection == TcpState.Established)
{
// Connection is OK
}
else
{
// No active tcp Connection to hostName:port
}
}
client.Close();
See Also:
TcpConnectionInformationon MSDN
IPGlobalProperties on MSDN
Description of TcpStatestates
Netstat on Wikipedia
另请参见:
TcpConnectionInformationMSDN上
IPGlobalPropertiesMSDN上
的说明TcpState规定
的Netstat上维基百科
And here it is as an extension method on TcpClient.
在这里它是作为 TcpClient 上的扩展方法。
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint));
return foo != null ? foo.State : TcpState.Unknown;
}
回答by Rawk
@uriel's answer works great for me, but I needed to code it in C++/CLI, which was not entirely trivial. Here is the (roughly equivalent) C++/CLI code, with a few robustness checks added in for good measure.
@uriel 的回答对我很有用,但我需要用 C++/CLI 对其进行编码,这并非微不足道。这是(大致等效的)C++/CLI 代码,其中添加了一些稳健性检查以进行良好的衡量。
using namespace System::Net::Sockets;
using namespace System::Net::NetworkInformation;
TcpState GetTcpConnectionState(TcpClient ^ tcpClient)
{
TcpState tcpState = TcpState::Unknown;
if (tcpClient != nullptr)
{
// Get all active TCP connections
IPGlobalProperties ^ ipProperties = IPGlobalProperties::GetIPGlobalProperties();
array<TcpConnectionInformation^> ^ tcpConnections = ipProperties->GetActiveTcpConnections();
if ((tcpConnections != nullptr) && (tcpConnections->Length > 0))
{
// Get the end points of the TCP connection in question
EndPoint ^ localEndPoint = tcpClient->Client->LocalEndPoint;
EndPoint ^ remoteEndPoint = tcpClient->Client->RemoteEndPoint;
// Run through all active TCP connections to locate TCP connection in question
for (int i = 0; i < tcpConnections->Length; i++)
{
if ((tcpConnections[i]->LocalEndPoint->Equals(localEndPoint)) && (tcpConnections[i]->RemoteEndPoint->Equals(remoteEndPoint)))
{
// Found active TCP connection in question
tcpState = tcpConnections[i]->State;
break;
}
}
}
}
return tcpState;
}
bool TcpConnected(TcpClient ^ tcpClient)
{
bool bTcpConnected = false;
if (tcpClient != nullptr)
{
if (GetTcpConnectionState(tcpClient) == TcpState::Established)
{
bTcpConnected = true;
}
}
return bTcpConnected;
}
Hopefully this will help somebody.
希望这会帮助某人。
回答by user391318
I have created this function and working for me to check if client is still connected with server.
我已经创建了这个函数并为我工作来检查客户端是否仍然与服务器连接。
/// <summary>
/// THIS FUNCTION WILL CHECK IF CLIENT IS STILL CONNECTED WITH SERVER.
/// </summary>
/// <returns>FALSE IF NOT CONNECTED ELSE TRUE</returns>
public bool isClientConnected()
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation c in tcpConnections)
{
TcpState stateOfConnection = c.State;
if (c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint) && c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint))
{
if (stateOfConnection == TcpState.Established)
{
return true;
}
else
{
return false;
}
}
}
return false;
}
回答by LionAM
In my case, I was sending some command to a server (running in a virtual machine on the same computer) and waiting for the response. However, if the server stopped unexpectedly while waiting, I did not get any notification. I tried the possibilities proposed by the other posters, but neither did work (it always said that the server is still connected). For me, the only thing that is working is to write 0 bytes to the stream:
就我而言,我正在向服务器(在同一台计算机上的虚拟机中运行)发送一些命令并等待响应。但是,如果服务器在等待时意外停止,我没有收到任何通知。我尝试了其他海报提出的可能性,但都没有奏效(它总是说服务器仍然连接着)。对我来说,唯一有效的是向流中写入 0 个字节:
var client = new TcpClient();
//... open the client
var stream = client.GetStream();
//... send something to the client
byte[] empty = { 0 };
//wait for response from server
while (client.Available == 0)
{
//throws a SocketException if the connection is closed by the server
stream.Write(empty, 0, 0);
Thread.Sleep(10);
}
回答by frankhommers
The solution of Peter Wone and uriel is very nice. But you also need to check on the Remote Endpoint, since you can have multiple open connections to your Local Endpoint.
Peter Wone 和 uriel 的解决方案非常好。但是您还需要检查远程端点,因为您可以有多个到本地端点的打开连接。
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint)
&& x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint)
);
return foo != null ? foo.State : TcpState.Unknown;
}
回答by Johan Franzén
As of 2019, in a cross-platform and async environment, I use the code below to continuosly check that the TCP channel is open. This check fires e.g. if the ethernet cable is pulled on my Windows machine, or if the Wifi is disabled on my Android device.
截至 2019 年,在跨平台和异步环境中,我使用下面的代码不断检查 TCP 通道是否打开。例如,如果以太网电缆被拉到我的 Windows 机器上,或者如果我的 Android 设备上的 Wifi 被禁用,则会触发此检查。
private async Task TestConnectionLoop()
{
byte[] buffer = new byte[1];
ArraySegment<byte> arraySegment = new ArraySegment<byte>(buffer, 0, 0);
SocketFlags flags = SocketFlags.None;
while (!_cancellationSource.Token.IsCancellationRequested)
{
try
{
await _soc.SendAsync(arraySegment, flags);
await Task.Delay(500);
}
catch (Exception e)
{
_cancellationSource.Cancel();
// Others can listen to the Cancellation Token or you
// can do other actions here
}
}
}