web-dev-qa-db-ja.com

C#では、TCPポートが使用可能かどうかを確認する方法は?

C#でTcpClientを使用するか、一般的にソケットに接続するには、どのように最初に特定のポートがマシンで空いているかを確認できますか?

詳細:これは私が使用するコードです:

TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
112
Ali

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.
202
jro

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つだけ許可されます。

41
Hans Passant

TCP接続を設定する場合、4タプル(ソースIP、ソースポート、宛先IP、宛先ポート)は一意である必要があります-これは、パケットが確実に右側に配信されるようにするためです。場所。

server側には、さらに1つのサーバープログラムのみが着信ポート番号にバインドできるという制限があります(1つのIPアドレスを想定します。マルチNICサーバーには他の権限がありますが、それらについて議論する必要はありません)ここに)。

したがって、サーバー側では、次のことを行います。

  • ソケットを作成します。
  • そのソケットをポートにバインドします。
  • そのポートでリッスンします。
  • そのポートで接続を受け入れます。また、複数の接続が入ることがあります(クライアントごとに1つ)。

クライアント側では、通常は少し簡単です。

  • ソケットを作成します。
  • 接続を開きます。クライアントが接続を開くと、IPアドレスとserverのポートが指定されます。 canソースポートを指定しますが、通常はゼロを使用するため、システムは自動的に空きポートを割り当てます。

noという要件があります。宛先IP /ポートは一意である必要があります。これにより、一度に1人だけがGoogleを使用できるようになり、ビジネスモデルがかなり破壊されます。

これは、ソースポートのみが異なる複数のセッションを設定し、チャンクを並行してダウンロードできるため、マルチセッションFTPのようなすばらしいこともできることを意味します。トレントは、各セッションの宛先が通常異なるという点で少し異なります。

そして、すべてのワッフル(申し訳ありませんが)の後、特定の質問に対する答えは、空きポートを指定する必要がないということです。送信元ポートを指定しない呼び出しでサーバーに接続している場合、ほとんど確実にカバーの下でゼロが使用され、システムは未使用のものを提供します。

19
paxdiablo
TcpClient c;

//I want to check here if port is free.
c = new TcpClient(ip, port);

...マシンで特定のポートが空いているかどうかを最初に確認するにはどうすればよいですか?

つまり、他のアプリケーションでは使用されていません。アプリケーションがポートを使用している場合、空きになるまで他のユーザーは使用できません。 –アリ

ここで何が起こっているのか誤解しています。

TcpClient(...)パラメータは、接続したいサーバーIPとサーバーポートのものです。

TcpClientは、サーバーと通信するために使用可能なプールから一時的なローカルポートを選択します。ローカルポートはwinsockレイヤーによって自動的に処理されるため、ローカルポートの可用性を確認する必要はありません。

上記のコードフラグメントを使用してサーバーに接続できない場合、問題は1つ以上の可能性があります。 (つまり、サーバーのIPやポートが間違っている、リモートサーバーが使用できないなど)

15
Indy9000

このヒントをありがとう。同じ機能が必要でしたが、ポートが使用されているかどうかを確認するためにサーバー側でこのコードに変更しました。

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

回答jroに感謝します。私は自分の使用のためにそれを微調整する必要がありました。ポートがリッスンされていて、必ずしもアクティブになっていないかどうかを確認する必要がありました。このために私は置き換えました

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

IPEndPoint[] objEndPoints = ipGlobalProperties.GetActiveTcpListeners();.  

ポート値が見つからないことを確認しながら、エンドポイントの配列を繰り返しました。

6
user336046
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);
}
5
Learning

netstat!これは、Windowsに同梱されているネットワークコマンドラインユーティリティです。現在確立されているすべての接続と、現在リッスンされているすべてのポートが表示されます。このプログラムを使用して確認できますが、コードからこれを行う場合は、System.Net.NetworkInformation名前空間を確認してください。 2.0の新しい名前空間です。そこにはいくつかのグッズがあります。しかし、最終的にコマンドnetstatで利用できるのと同じ種類の情報を取得したい場合は、P/Invokeを実行する必要があります...

更新:System.Net.NetworkInformation

その名前空間には、ネットワークに関することを理解するために使用できるクラスの束が含まれています。

古いコードを見つけることができませんでしたが、自分で似たようなものを書くことができると思います。まずは IP Helper API を確認してください。 GetTcpTable WINAPI関数のGoogleMSDN。P/ Invokeを使用して、必要な情報が得られるまで列挙します。

3
John Leidegren

ipGlobalProperties.GetActiveTcpConnections()はリッスン状態の接続を返しません。

ポートはリスニングに使用できますが、ポートが接続されていない場合、上記の方法は機能しません。

2
Broken Pipe

あまり間違えていなければ、System.Network.whateverを使用して確認できます。

ただし、これには常に競合状態が発生します。

標準的なチェック方法は、そのポートでリッスンすることです。ポートが開いていないというエラーが表示された場合。

I 思考これは、bind()とlisten()が2つの別個のシステムコールである理由の一部です。

2
Joshua

利用可能なポートから私は除外します:

  • アクティブTCP接続
  • アクティブTCPリスナー
  • アクティブなUDPリスナー

次のインポートで:

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
2
Simone

あなたは言う

つまり、他のアプリケーションでは使用されていません。アプリケーションがポートを使用している場合、空きになるまで他のユーザーは使用できません。

ただし、何かがリスンしている場合、他の人がポートを使用している間はいつでもポートに接続できます。そうしないと、httpポート80が混乱します。

もしあなたの

   c = new TcpClient(ip, port);

失敗すると、何も聞いていません。それ以外の場合、他のマシン/アプリケーションがそのIPおよびポートに対して開いているソケットを持っている場合でも、接続します。

2
Moose
    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;
    }
1

チェックを行ってから、接続を確立しようとする瞬間までの時間枠に注意してください-古典的な TOCTOU 。接続してみませんか?失敗した場合、ポートが利用できないことがわかります。

1
ya23

リモートTCPサービスに接続するためにローカルマシンでどのポートが開いているかを知る必要はありません(特定のローカルポートを使用する場合を除きますが、通常はそうではありません)。

すべてのTCP/IP接続は、リモートIP、リモートポート番号、ローカルIP、ローカルポート番号の4つの値で識別されますが、接続を確立するために必要なのはリモートIPとリモートポート番号のみです。

を使用してtcp接続を作成するとき

 TcpClient c; 
 c = new TcpClient(remote_ip、remote_port); 
 

システムは、多くの空きローカルポート番号の1つを接続に自動的に割り当てます。何もする必要はありません。リモートポートが開いているかどうかを確認することもできます。しかし、単に接続しようとするよりも、それを行うより良い方法はありません。

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.");
   }
 }
}
0
Yuriy Stanchev

エラーコード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;
}
0
Mohsen