C#では、TCPポートが使用可能かどうかを確認するにはどうすればよいですか?


120

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

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

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

2
ここで「無料」とはどういう意味ですか?接続しようとして失敗した場合、おそらく何も聞いていなかったことを意味します。
Jon Skeet、

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

接続しようとしているサーバーは何ですか?あなたはそれを書きましたか、それとも既存のサーバーですか?
悲しむ

3
多くの回答で述べられているように、あなたはすべてを後方に持っています。ローカルポートとリモートポートはまったく別のものです。特に、この答えは、それをうまく説明:stackoverflow.com/questions/570098/...
bzlm

回答:


217

を使用しているため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.

38
チェックしている間、別のプロセスがそのポートにバインドする可能性があることに注意してください。
セルゲイ

2
これは質問とどのように関連していますか?この回答は、リモートポートではなくローカルポートを扱います。
bzlm 2009

6
OPの要求に答えるという点で重要です。ローカル/リモートの違いにもかかわらず(完全に同意します)、OPの要件は、「空き」のポートを持つ新しいTcpClientを作成することでした。
jro 2009

8
このコードはアクティブな接続のみをチェックすることに注意してください。パケットを送受信していない接続は表示されません。
JoeBilly、2011年

29
上記のコードの結果をと比較してくださいnetstat -a -b。にはLISTENING接続が存在しないことに注意してくださいGetActiveTcpConnections()。また、にチェックすべきSystem.Net.IPEndPoints[]で返されるipGlobalProperties.GetActiveTcpListeners();
マイク・デクラーク

44

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


それも私がそれをしようとしていたところです。誰かが間違いなくここで混乱しており、それが私である可能性があります。
ムース

3
クライアントも特定のポートを必要とする可能性がありますが、一般的ではありません。
Dave Van den Eynde、2009

@DaveVandenEyndeは、「クライアント」がその特定のポートで実際に「サービス」を提供している場合にのみ発生する可能性があります(少なくとも、TCPに関する限り、「ポート」では「サーバー」にします)。-クライアントTCP接続がある場合、発信ポートを制御できません。TCPスタックは発信ポートを割り当てますが、それを制御することはできません。
BrainSlugs83

1
:最も確かにすることができますBrainSlugs83あなた@ stackoverflow.com/questions/2869840/...
デイヴ・ヴァン・デンEynde

これは、ポートが空いているかどうかを確認するための有効なコードです。成功した場合に備えてTcpListenerをStop()することを忘れないでください(同じTcpListenerオブジェクトを使用してポートでの待機を開始するつもりがない場合)。
bgh

19

TCP接続をセットアップする場合、4タプル(source-ip、source-port、dest-ip、dest-port)は一意である必要があります。これは、パケットが正しい場所に配信されるようにするためです。

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

したがって、サーバー側では次のようになります。

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

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

  • ソケットを作成します。
  • 接続を開きます。クライアントが接続を開くときに、サーバーのIPアドレスとポートを指定します。それはすることができ、その送信元ポートを指定しますが、通常は自動的にそれを空いているポートを割り当てるシステムになり、ゼロを使用しています。

宛先IP /ポートが一意である必要はありません。一度に1人しかGoogleを使用できず、ビジネスモデルがかなり破壊されるためです。

つまり、ソースポートのみが異なる複数のセッションをセットアップし、チャンクを並行してダウンロードできるため、マルチセッションFTPなどの不思議なことをすることさえできます。トレントは、各セッションの宛先が通常異なるという点で少し異なります。

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


15
TcpClient c;

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

...どのようにしたら、特定のポートがマシン上で空いているかを最初に確認できますか?

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

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

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

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

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


15

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

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

これは必要ありません。ポート0を指定するだけです。
ローンの侯爵

ソースコードコメントの注記:「これはnetstatコマンドラインアプリケーションによって提供される情報と同じです」-嘘です。netstatコマンドがポート(-anb)を使用してアプリケーションのPIDを提供するのと同じ情報を提供せず、パラメーターなしで外部接続と状態を表示します。
Kraang Prime

6

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

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

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

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


自分で聞いてみてください。これは必要ありません。
ローン侯爵

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

ソケットに接続しようとしているのは私です。質問をより明確にするために編集しました。
アリ

私はこのコードが一番好きです。これは実際にソケットへのTCP接続を開いて、誰かが相手側でリッスンしているかどうかを調べるだけです。そして、「リモートホストでポートが開いているかどうかをテストする」ときに、多くの人が実際にこれを望んでいると思います。ただし、上記のコードにはバグがあります。(sock.Connected == true)の場合、ポートは接続用に開いており、サーバーのようなソフトウェアがそこで待機しています。10061 ErrorCodeのSocketExceptionがある場合(メッセージ "(0x80004005):ターゲットマシンがアクティブに拒否したため、接続を確立できませんでした"と、ポートが閉じます!
Csaba Toth

したがって、それはコードスニペットではその逆です。別のメモ:IPアドレスのみを持つ仮想サーバーがあるテストセットアップで誰かがDns.GetHostEntryを試してみると、例外が発生します。
Csaba Toth

3

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

更新:System.Net.NetworkInformation

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

私はその古いコードを見つけることができませんでしたが、自分で同様の何かを書くことができると思います。まず、IP Helper APIをチェックしてください。GetTcpTable WINAPI関数用のGoogle MSDN およびP / Invokeを使用して、必要な情報が得られるまで列挙します。


私は.NET 3.5を使用していますが、それを罰することはできません。
アリ

私はあなたのためにそれを微てみましょう:msdn.microsoft.com/en-us/library/...
bzlm

3

私がそれほど間違っていない場合は、System.Network.whateverを使用して確認できます。

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

正規のチェック方法は、そのポートで待機することです。エラーが発生した場合は、ポートが開いていませんでした。

私が考えるこれは、バインド()とlisten()は、2回の独立したシステムコールである理由の一部です。


2

あなたは言う

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

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

もしあなたの

   c = new TcpClient(ip, port);

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


私のアプリケーションの試みは、両方のアプリケーションが一つのポートを使用してデータを送信することはできませんので、再びそれが失敗するポート10を使用して接続するためのポート10と、自分のアプリケーションの試みの別のインスタンスを使用して接続する場合は、データを受信することになると、異なるポート80、すなわち
アリ

どう違うの?アプリケーションのポート10で何をリッスンしていますか?
ムース

2番目のインスタンスが接続を試みたときに失敗した場合、それはリスニングアプリケーションであり、アプリケーションではありません。
ムース

2

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

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


上記のどの方法ですか?これはどのように質問に答えますか?
ローン侯爵

2

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

  • アクティブな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

dotnet core 3.1で空きポートを見つけるという正確な質問に答えるために(これは私のユニットテストで必要なものです)、私はこれを思いつきました

public static int GetAvailablePort(IPAddress ip) {
        TcpListener l = new TcpListener(ip, 0);
        l.Start();
        int port = ((IPEndPoint)l.LocalEndpoint).Port;
        l.Stop();
        Log.Info($"Available port found: {port}");
        return port;
    }

注:ポート0に関する@ user207421のコメントに基づいて、私はこれを検索して見つけ、わずかに変更しました。


1

チェックを行ってから接続を試行するまでの時間枠には、いくつかのプロセスでポート-クラシックTOCTOUが使用される場合があることに注意してください。接続してみませんか?失敗した場合は、ポートが利用できないことがわかります。


4
TOCTOUはYALAIHHOBIKTPBI(まだ聞いたことのないもう1つの長い略語ですが、その背後にある現象を知っています)
Csaba Toth

1

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

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

を使用してtcp接続を作成する場合

TcpClient c;
c =新しいTcpClient(remote_ip、remote_port);

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


これは、指定されたソケットのセットをチェックするのに適しています。問題は、たった1つのソケットについてです(どのポート番号が未定か(?))
Csaba Toth 2013年

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

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

1
コードを投稿するときは、それが問題の解決策である理由を詳しく説明してください。コードだけでは情報が少なすぎて、回答が見過ごされる可能性があります。
Glubus

0

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

-2

これを試してください、私の場合、作成されたオブジェクトのポート番号が利用できなかったので、これを思いつきました

IPEndPoint endPoint;
int port = 1;
while (true)
{
    try
    {
        endPoint = new IPEndPoint(IPAddress.Any, port);
        break;
    }
    catch (SocketException)
    {
         port++;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.