如何检查TcpClient连接是否已关闭?

时间:2009-09-07 03:41:22

标签: c# sockets tcpclient networkstream

我正在玩TcpClient,我试图弄清楚如何在连接断开时使Connected属性为false。

我试过

NetworkStream ns = client.GetStream();
ns.Write(new byte[1], 0, 0);

但是如果TcpClient断开连接,它仍然不会显示。你会如何使用TcpClient进行此操作?

9 个答案:

答案 0 :(得分:40)

我不建议您尝试编写仅用于测试套接字。并且不要在.NET的Connected属性上进行中继。

如果您想知道远程终点是否仍然有效,可以使用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();

参见:
MSDN上的TcpConnectionInformation
MSDN上的IPGlobalProperties
TcpState州的描述
Netstat Wikipedia


这里它是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;
}

答案 1 :(得分:7)

据我所知/记得没有办法测试套接字是否已连接而不是读取或写入。

我根本没有使用过TcpClient,但是如果远程端正常关闭,Socket类将从调用Read返回0。 如果远程端没有正常关闭[我认为]你得到超时异常,不记得抱歉的类型。

使用像“if(socket.Connected) { socket.Write(...) }这样的代码会产生竞争条件。你最好只调用socket.Write并处理异常和/或断开连接。

答案 2 :(得分:2)

我已经创建了这个功能,并且正在为我检查客户端是否仍与服务器连接。

/// <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;


}

答案 3 :(得分:2)

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;
    }

答案 4 :(得分:1)

@ 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;
}

希望这会对某人有所帮助。

答案 5 :(得分:0)

就我而言,我正在向服务器发送一些命令(在同一台计算机上的虚拟机中运行)并等待响应。但是,如果服务器在等待时意外停止,我没有收到任何通知。我尝试了其他海报提出的可能性,但都没有工作(它总是说服务器仍然连接)。对我来说,唯一有效的是将0字节写入流:

MyImplicitJsonProvider[GetX]

答案 6 :(得分:0)

从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
        }
    }
}

答案 7 :(得分:0)

请注意,我发现GSF.Communication的{​​{1}}包装器很有帮助,因为它具有System.Net.Sockets.TcpClient属性,该属性指示套接字是打开/连接还是关闭/断开。您可以在此处找到有关NuGet软件包的详细信息:

https://github.com/GridProtectionAlliance/gsf

在这里,您可以设置一个简单的TCP套接字并测试它是否已连接:

CurrentState

答案 8 :(得分:-1)

试试这个,它对我有用

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();
        }

    }

我使用了Timer,因为我想定期检查连接状态 而不是一个带有听力代码的LOOP [我觉得它正在减慢发送 - 接收过程]