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();
関連項目:
TcpConnectionInformation MSDNで
IPGlobalProperties MSDNで
TcpState 状態の説明
Netstat on 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;
}
私が知っている/覚えている限り、ソケットが接続されているかどうかをテストする方法は、読み取りまたは書き込み以外にはありません。
私は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;
}
ピーターワインとウリエルの解決策は非常に素晴らしいです。ただし、ローカルエンドポイントへの接続が複数開いている可能性があるため、リモートエンドポイントも確認する必要があります。
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;
}
@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;
}
うまくいけば、これは誰かを助けるでしょう。
私の場合、サーバー(同じコンピューター上の仮想マシンで実行中)にコマンドを送信して、応答を待っていました。ただし、待機中にサーバーが予期せず停止した場合、通知はありませんでした。他の投稿者が提案した可能性を試してみましたが、どちらも機能しませんでした(サーバーはまだ接続されていると常に言っていました)。私にとって、機能しているのはストリームに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);
}