C# 如何检查TCP客户端连接是否已关闭?

C# 如何检查TCP客户端连接是否已关闭?,c#,sockets,tcpclient,networkstream,C#,Sockets,Tcpclient,Networkstream,我在玩弄TcpClient,试图弄清楚如何在连接断开时使Connected属性为false 我试过了 NetworkStream ns = client.GetStream(); ns.Write(new byte[1], 0, 0); 但它仍然不会显示TCP客户端是否已断开连接。您将如何使用TCP客户端进行此操作?据我所知/记得,除了读取或写入套接字之外,无法测试是否连接了套接字 我根本没有使用TcpClient,但是如果远程端正常关闭,Socket类将从Read调用返回0。 如果远程端没有

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

我试过了

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

但它仍然不会显示TCP客户端是否已断开连接。您将如何使用TCP客户端进行此操作?

据我所知/记得,除了读取或写入套接字之外,无法测试是否连接了套接字

我根本没有使用TcpClient,但是如果远程端正常关闭,Socket类将从Read调用返回0。 如果远程端没有正常关闭[我认为]会出现超时异常,无法记住类型抱歉


使用类似于“
if(socket.Connected){socket.Write(…)}”的代码创建竞争条件。您最好只调用套接字。编写并处理异常和/或断开连接。

试试这个,它对我有用

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

    }
我使用定时器是因为我想定期检查连接状态
而且不在侦听代码的循环中[我觉得这会减慢发送-接收过程]

我不建议您仅为测试套接字而尝试编写。也不要依赖.NET的连接属性

如果您想知道远程端点是否仍处于活动状态,可以使用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上
在MSDN上
状态说明
netstaton


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

@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;
}
使用名称空间System::Net::Sockets;
使用名称空间System::Net::NetworkInformation;
TcpState GetTcpConnectionState(TCP客户端^TCP客户端)
{
TcpState TcpState=TcpState::未知;
if(tcpClient!=nullptr)
{
//获取所有活动的TCP连接
IPGlobalProperties ^ipProperties=IPGlobalProperties::GetIPGlobalProperties();
数组^tcpConnections=ipProperties->GetActiveTcpConnections();
如果((tcpConnections!=nullptr)&&(tcpConnections->Length>0))
{
//获取有问题的TCP连接的端点
端点^localEndPoint=tcpClient->Client->localEndPoint;
端点^remoteEndPoint=tcpClient->Client->remoteEndPoint;
//运行所有活动的TCP连接以查找有问题的TCP连接
对于(int i=0;iLength;i++)
{
if((tcpConnections[i]->LocalEndPoint->Equals(LocalEndPoint))&&(tcpConnections[i]->RemoteEndPoint->Equals(RemoteEndPoint)))
{
//发现有问题的活动TCP连接
tcpState=TCP连接[i]->状态;
打破
}
}
}
}
返回tcpState;
}
bool TCP已连接(TCP客户端^TCP客户端)
{
bool bTcpConnected=false;
if(tcpClient!=nullptr)
{
if(gettcpcConnectionState(tcpClient)=TcpState::已建立)
{
bTcpConnected=true;
}
}
返回bTcpConnected;
}

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

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

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


}
//
///此函数将检查客户端是否仍与服务器连接。
/// 
///如果未连接,则为FALSE,否则为TRUE
公共bool isClientConnected()
{
IPGlobalProperties ipProperties=IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[]tcpConnections=ipProperties.GetActiveTcpConnections();
foreach(TCP连接中的TCP连接信息c)
{
TcpState连接状态=c.状态;
if(c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint)和&c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint))
{
if(连接状态==TcpState.builded)
{
返回true;
}
其他的
{
返回false;
}
}
}
返回false;
}

在我的例子中,我向服务器发送了一些命令(在同一台计算机上的虚拟机中运行)并等待响应。但是,如果服务器在等待时意外停止,我不会收到任何通知。我尝试了其他海报提出的可能性,但都没有成功(总是说服务器仍然连接)。对我来说,唯一有效的方法是将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);
}

彼得·沃恩和乌列尔的解决方案非常好。但是您还需要检查远程端点,因为您可以有多个到本地端点的开放连接

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

到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
        }
    }
}
private异步任务TestConnectionLoop()
{
字节[]缓冲区=新字节[1];
ArraySegment ArraySegment=新的ArraySegment(缓冲区,0,0);
SocketFlags flags=SocketFlags.None;
while(!\u cancellationSource.Token.IsCancellationRequested)
{
尝试
{
wait _soc.SendAsync(arraySegment,flags);
等待任务。延迟(500);
}
捕获(例外e)
{
_cancellationSource.Cancel();
//其他人可以收听取消令牌或您
//您可以在这里执行其他操作
}
}
}

请注意,我发现
System.Net.Sockets.TcpClient
GSF.Communication
包装器非常有用,因为它有一个
CurrentState
属性,指示套接字是打开/连接的还是关闭/断开的。您可以找到详细信息
    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)));
    }