C#でTcpClientを使用するか、一般的にソケットに接続するには、どのように最初に特定のポートがマシンで空いているかを確認できますか?
詳細:これは私が使用するコードです:
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
TcpClient
を使用しているため、開いているTCPポートをチェックしていることになります。 System.Net.NetworkInformation 名前空間で利用できる優れたオブジェクトがたくさんあります。
IPGlobalProperties
オブジェクトを使用してTcpConnectionInformation
オブジェクトの配列を取得し、エンドポイントIPとポートについて問い合わせることができます。
int port = 456; //<--- This is your value
bool isAvailable = true;
// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form. We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
{
if (tcpi.LocalEndPoint.Port==port)
{
isAvailable = false;
break;
}
}
// At this point, if isAvailable is true, we can proceed accordingly.
Intertubeの反対側にいます。特定のポートを1つだけ開くことができるのはサーバーです。いくつかのコード:
IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try {
TcpListener tcpListener = new TcpListener(ipAddress, 666);
tcpListener.Start();
}
catch (SocketException ex) {
MessageBox.Show(ex.Message, "kaboom");
}
失敗する:
通常、各ソケットアドレス(プロトコル/ネットワークアドレス/ポート)の使用は1つだけ許可されます。
TCP接続を設定する場合、4タプル(ソースIP、ソースポート、宛先IP、宛先ポート)は一意である必要があります-これは、パケットが確実に右側に配信されるようにするためです。場所。
server側には、さらに1つのサーバープログラムのみが着信ポート番号にバインドできるという制限があります(1つのIPアドレスを想定します。マルチNICサーバーには他の権限がありますが、それらについて議論する必要はありません)ここに)。
したがって、サーバー側では、次のことを行います。
クライアント側では、通常は少し簡単です。
noという要件があります。宛先IP /ポートは一意である必要があります。これにより、一度に1人だけがGoogleを使用できるようになり、ビジネスモデルがかなり破壊されます。
これは、ソースポートのみが異なる複数のセッションを設定し、チャンクを並行してダウンロードできるため、マルチセッションFTPのようなすばらしいこともできることを意味します。トレントは、各セッションの宛先が通常異なるという点で少し異なります。
そして、すべてのワッフル(申し訳ありませんが)の後、特定の質問に対する答えは、空きポートを指定する必要がないということです。送信元ポートを指定しない呼び出しでサーバーに接続している場合、ほとんど確実にカバーの下でゼロが使用され、システムは未使用のものを提供します。
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
...マシンで特定のポートが空いているかどうかを最初に確認するにはどうすればよいですか?
つまり、他のアプリケーションでは使用されていません。アプリケーションがポートを使用している場合、空きになるまで他のユーザーは使用できません。 –アリ
ここで何が起こっているのか誤解しています。
TcpClient(...)パラメータは、接続したいサーバーIPとサーバーポートのものです。
TcpClientは、サーバーと通信するために使用可能なプールから一時的なローカルポートを選択します。ローカルポートはwinsockレイヤーによって自動的に処理されるため、ローカルポートの可用性を確認する必要はありません。
上記のコードフラグメントを使用してサーバーに接続できない場合、問題は1つ以上の可能性があります。 (つまり、サーバーのIPやポートが間違っている、リモートサーバーが使用できないなど)
このヒントをありがとう。同じ機能が必要でしたが、ポートが使用されているかどうかを確認するためにサーバー側でこのコードに変更しました。
private bool CheckAvailableServerPort(int port) {
LOG.InfoFormat("Checking Port {0}", port);
bool isAvailable = true;
// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form. We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();
foreach (IPEndPoint endpoint in tcpConnInfoArray) {
if (endpoint.Port == port) {
isAvailable = false;
break;
}
}
LOG.InfoFormat("Port {0} available = {1}", port, isAvailable);
return isAvailable;
}
回答jroに感謝します。私は自分の使用のためにそれを微調整する必要がありました。ポートがリッスンされていて、必ずしもアクティブになっていないかどうかを確認する必要がありました。このために私は置き換えました
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
と
IPEndPoint[] objEndPoints = ipGlobalProperties.GetActiveTcpListeners();.
ポート値が見つからないことを確認しながら、エンドポイントの配列を繰り返しました。
string hostname = "localhost";
int portno = 9081;
IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];
try
{
System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) // Port is in use and connection is successful
MessageBox.Show("Port is Closed");
sock.Close();
}
catch (System.Net.Sockets.SocketException ex)
{
if (ex.ErrorCode == 10061) // Port is unused and could not establish connection
MessageBox.Show("Port is Open!");
else
MessageBox.Show(ex.Message);
}
netstat!これは、Windowsに同梱されているネットワークコマンドラインユーティリティです。現在確立されているすべての接続と、現在リッスンされているすべてのポートが表示されます。このプログラムを使用して確認できますが、コードからこれを行う場合は、System.Net.NetworkInformation名前空間を確認してください。 2.0の新しい名前空間です。そこにはいくつかのグッズがあります。しかし、最終的にコマンドnetstatで利用できるのと同じ種類の情報を取得したい場合は、P/Invokeを実行する必要があります...
その名前空間には、ネットワークに関することを理解するために使用できるクラスの束が含まれています。
古いコードを見つけることができませんでしたが、自分で似たようなものを書くことができると思います。まずは IP Helper API を確認してください。 GetTcpTable WINAPI関数のGoogleMSDN。P/ Invokeを使用して、必要な情報が得られるまで列挙します。
ipGlobalProperties.GetActiveTcpConnections()
はリッスン状態の接続を返しません。
ポートはリスニングに使用できますが、ポートが接続されていない場合、上記の方法は機能しません。
あまり間違えていなければ、System.Network.whateverを使用して確認できます。
ただし、これには常に競合状態が発生します。
標準的なチェック方法は、そのポートでリッスンすることです。ポートが開いていないというエラーが表示された場合。
I 思考これは、bind()とlisten()が2つの別個のシステムコールである理由の一部です。
利用可能なポートから私は除外します:
次のインポートで:
using System.Net.NetworkInformation;
次の関数を使用して、ポートが使用可能かどうかを確認できます。
private bool isPortAvalaible(int myPort)
{
var avalaiblePorts = new List<int>();
var properties = IPGlobalProperties.GetIPGlobalProperties();
// Active connections
var connections = properties.GetActiveTcpConnections();
avalaiblePorts.AddRange(connections);
// Active tcp listners
var endPointsTcp = properties.GetActiveTcpListeners();
avalaiblePorts.AddRange(endPointsTcp);
// Active udp listeners
var endPointsUdp = properties.GetActiveUdpListeners();
avalaiblePorts.AddRange(endPointsUdp);
foreach (int p in avalaiblePorts){
if (p == myPort) return false;
}
return true;
}
VB.NETを使用するユーザー向けに、同様の機能を提供します。
Imports System.Net.NetworkInformation
Private Function isPortAvalaible(ByVal myPort As Integer) As Boolean
Dim props As IPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties()
' ignore active connections
Dim tcpConnInfoArray() As TcpConnectionInformation = props.GetActiveTcpConnections()
For Each tcpi As Net.NetworkInformation.TcpConnectionInformation In tcpConnInfoArray
If tcpi.LocalEndPoint.Port = myPort Then
Return False
End If
Next tcpi
' ignore active TCP listeners
Dim activeTcpListeners() As Net.IPEndPoint = props.GetActiveTcpListeners
For Each tcpListener As Net.IPEndPoint In activeTcpListeners
If tcpListener.Port = myPort Then
Return False
End If
Next tcpListener
' ignore active UPD listeners
Dim activeUdpListeners() As Net.IPEndPoint = props.GetActiveUdpListeners
For Each udpListener As Net.IPEndPoint In activeUdpListeners
If udpListener.Port = myPort Then
Return False
End If
Next udpListener
Return True
End Function
あなたは言う
つまり、他のアプリケーションでは使用されていません。アプリケーションがポートを使用している場合、空きになるまで他のユーザーは使用できません。
ただし、何かがリスンしている場合、他の人がポートを使用している間はいつでもポートに接続できます。そうしないと、httpポート80が混乱します。
もしあなたの
c = new TcpClient(ip, port);
失敗すると、何も聞いていません。それ以外の場合、他のマシン/アプリケーションがそのIPおよびポートに対して開いているソケットを持っている場合でも、接続します。
public static bool TestOpenPort(int Port)
{
var tcpListener = default(TcpListener);
try
{
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
tcpListener = new TcpListener(ipAddress, Port);
tcpListener.Start();
return true;
}
catch (SocketException)
{
}
finally
{
if (tcpListener != null)
tcpListener.Stop();
}
return false;
}
チェックを行ってから、接続を確立しようとする瞬間までの時間枠に注意してください-古典的な TOCTOU 。接続してみませんか?失敗した場合、ポートが利用できないことがわかります。
リモートTCPサービスに接続するためにローカルマシンでどのポートが開いているかを知る必要はありません(特定のローカルポートを使用する場合を除きますが、通常はそうではありません)。
すべてのTCP/IP接続は、リモートIP、リモートポート番号、ローカルIP、ローカルポート番号の4つの値で識別されますが、接続を確立するために必要なのはリモートIPとリモートポート番号のみです。
を使用してtcp接続を作成するとき
TcpClient c; c = new TcpClient(remote_ip、remote_port);
システムは、多くの空きローカルポート番号の1つを接続に自動的に割り当てます。何もする必要はありません。リモートポートが開いているかどうかを確認することもできます。しかし、単に接続しようとするよりも、それを行うより良い方法はありません。
test_connection("ip", port);
public void test_connection(String hostname, int portno) {
IPAddress ipa = (IPAddress)Dns.GetHostAddresses(hostname)[0];
try {
System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) {
MessageBox.Show("Port is in use");
}
sock.Close();
}
catch (System.Net.Sockets.SocketException ex) {
if (ex.ErrorCode == 10060) {
MessageBox.Show("No connection.");
}
}
}
エラーコード10048を確認します
try
{
TcpListener tcpListener = new TcpListener(ipAddress, portNumber);
tcpListener.Start();
}
catch(SocketException ex)
{
if(ex.ErrorCode == 10048)
{
MessageBox.Show("Port " + portNumber + " is currently in use.");
}
return;
}