私は TcpClient をいじっていて、接続が切断されたときに Connected プロパティを false にする方法を見つけようとしています。
やってみた
NetworkStream ns = client.GetStream();
ns.Write(new byte[1], 0, 0);
ただし、TcpClient が切断されている場合は表示されません。TcpClient を使用してこれを行うにはどうすればよいでしょうか。
私は TcpClient をいじっていて、接続が切断されたときに Connected プロパティを false にする方法を見つけようとしています。
やってみた
NetworkStream ns = client.GetStream();
ns.Write(new byte[1], 0, 0);
ただし、TcpClient が切断されている場合は表示されません。TcpClient を使用してこれを行うにはどうすればよいでしょうか。
ソケットをテストするためだけに書き込みを試みることはお勧めしません。また、.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;
}
私が知っている/覚えている限り、ソケットへの読み取りまたは書き込み以外に、ソケットが接続されているかどうかをテストする方法はありません。
私は TcpClient をまったく使用していませんが、リモート エンドが正常にシャットダウンされている場合、Socket クラスは Read の呼び出しから 0 を返します。リモート エンドが正常にシャットダウンしない場合 [私は思う] タイムアウト例外が発生します。申し訳ありませんが、タイプを思い出せません。
' のようなコードを使用if(socket.Connected) { socket.Write(...) }
すると、競合状態が発生します。socket.Write を呼び出して、例外や切断を処理するだけのほうがよいでしょう。
私はこの関数を作成し、クライアントがまだサーバーに接続されているかどうかを確認するために働いています。
/// <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;
}
ソケットが開いている/接続されているか、閉じている/切断されているかを示すプロパティがあるため、 GSF.Communication
wrapperSystem.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)));
}
これを試してください、それは私のために働きます
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();
}
}
タイマーを使用したのは、定期的に接続状態を確認し、リッスン コードを使用したループではなく、[送受信プロセスが遅くなったと感じた] ためです。