36

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

我试着做

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

但是如果 TcpClient 断开连接,它仍然不会显示我。你将如何使用 TcpClient 来解决这个问题?

4

9 回答 9

56

我不建议您尝试仅为测试套接字而编写。也不要在 .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状态
的描述Wikipedia 上的 Netstat


这里它作为 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;
}
于 2013-10-31T12:15:48.637 回答
9

据我所知/记得,除了读取或写入之外,没有其他方法可以测试套接字是否已连接。

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

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

于 2009-09-07T08:40:34.487 回答
6

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;
    }
于 2017-05-29T12:22:26.143 回答
3

我已经创建了这个函数并为我检查客户端是否仍然与服务器连接。

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


}
于 2015-10-19T08:15:23.067 回答
2

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

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

于 2015-03-19T17:48:48.620 回答
1

截至 2019 年,在跨平台和异步环境中,我使用下面的代码持续检查 TCP 通道是否打开。例如,如果以太网电缆被拉到我的 Windows 机器上,或者 Wifi 在我的 Android 设备上被禁用,则会触发此检查。

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
        }
    }
}
于 2019-11-10T18:17:44.017 回答
1

请注意,我发现GSF.Communicationwrapper forSystem.Net.Sockets.TcpClient很有帮助,因为它具有CurrentState指示套接字是打开/连接还是关闭/断开的属性。您可以在此处找到有关 NuGet 包的详细信息:

https://github.com/GridProtectionAlliance/gsf

以下是如何设置一个简单的 TCP 套接字并测试它是否已连接:

    GSF.Communication.TcpClient tcpClient;

    void TestTcpConnectivity() 
    {
        tcpClient = new GSF.Communication.TcpClient();
        string myTCPServer = "localhost";
        string myTCPport = "8080";
        tcpClient.MaxConnectionAttempts = 5;
        tcpClient.ConnectionAttempt += s_client_ConnectionAttempt;
        tcpClient.ReceiveDataComplete += s_client_ReceiveDataComplete;
        tcpClient.ConnectionException += s_client_ConnectionException;
        tcpClient.ConnectionEstablished += s_client_ConnectionEstablished;
        tcpClient.ConnectionTerminated += s_client_ConnectionTerminated;
        
        tcpClient.ConnectionString = "Server=" + myTCPServer + ":" + myTCPport;
        tcpClient.Initialize();
        tcpClient.Connect();        

        Thread.Sleep(250);
        
        if (tcpClient.CurrentState == ClientState.Connected)
        {
            Debug.WriteLine("Socket is connected");
            // Do more stuff 
        } 
        else if (tcpClient.CurrentState == ClientState.Disconnected)
        {
            Debug.WriteLine(@"Socket didn't connect");
            // Do other stuff or try again to connect 
        }
    }
    
    void s_client_ConnectionAttempt(object sender, EventArgs e)
    {
        Debug.WriteLine("Client is connecting to server.");
    }

    void s_client_ConnectionException(object sender, EventArgs e)
    {
        Debug.WriteLine("Client exception - {0}.", e.Argument.Message);
    }

    void s_client_ConnectionEstablished(object sender, EventArgs e)
    {
        Debug.WriteLine("Client connected to server.");
    }

    void s_client_ConnectionTerminated(object sender, EventArgs e)
    {
        Debug.WriteLine("Client disconnected from server.");
    }

    void s_client_ReceiveDataComplete(object sender, GSF.EventArgs<byte[], int> e)
    {
        Debug.WriteLine(string.Format("Received data - {0}.", tcpClient.TextEncoding.GetString(e.Argument1, 0, e.Argument2)));
    }       
于 2020-08-19T17:11:49.690 回答
0

试试这个,它对我有用

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 是因为,我想定期检查连接状态,而不是在带有监听代码的循环中 [我觉得它减慢了发送-接收过程]

于 2011-12-25T19:11:41.787 回答
0

就我而言,我正在向服务器发送一些命令(在同一台计算机上的虚拟机中运行)并等待响应。但是,如果服务器在等待时意外停止,我没有收到任何通知。我尝试了其他海报提出的可能性,但都没有奏效(它总是说服务器仍然连接)。对我来说,唯一有效的是将 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);
}
于 2017-03-29T14:16:18.057 回答