Wie kann in C # überprüft werden, ob ein TCP-Port verfügbar ist?

120

Wie kann ich in C # zuerst überprüfen, ob ein bestimmter Port auf meinem Computer frei ist, um einen TcpClient zu verwenden oder allgemein eine Verbindung zu einem Socket herzustellen?

Weitere Informationen: Dies ist der Code, den ich verwende:

TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
Ali
quelle
2
Was meinst du hier mit "frei"? Wenn Sie versuchen, eine Verbindung herzustellen, und dies fehlschlägt, bedeutet dies wahrscheinlich, dass nichts zugehört hat.
Jon Skeet
2
Ich meine, dass es von keiner anderen Anwendung verwendet wird. Wenn eine Anwendung einen Port verwendet, können andere ihn erst verwenden, wenn er kostenlos ist.
Ali
Mit welchem ​​Server möchten Sie eine Verbindung herstellen? Hast du es geschrieben oder ist es ein vorhandener Server?
Trauer
3
Wie in vielen Antworten angegeben, haben Sie alles rückwärts. Lokale Ports und Remote-Ports sind zwei völlig verschiedene Dinge. Diese Antwort erklärt es besonders gut: stackoverflow.com/questions/570098/…
bzlm

Antworten:

217

Da Sie a verwenden TcpClient, bedeutet dies, dass Sie offene TCP-Ports überprüfen. Im System.Net.NetworkInformation- Namespace sind viele gute Objekte verfügbar .

Verwenden Sie das IPGlobalPropertiesObjekt, um zu einem Array von TcpConnectionInformationObjekten zu gelangen, die Sie dann nach Endpunkt-IP und Port abfragen können.


 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.
jro
quelle
38
Beachten Sie, dass ein anderer Prozess während der Überprüfung an diesen Port gebunden werden kann.
Serguei
2
Wie ist das für die Frage relevant? Diese Antwort bezieht sich auf lokale Ports, nicht auf Remote- Ports.
bzlm
6
Es ist insofern relevant, als es die Anfrage des OP beantwortet. Ungeachtet des lokalen / entfernten Unterschieds (stimme Ihnen voll und ganz zu) bestand die Anforderung des OP darin, einen neuen TcpClient mit einem "freien" Port zu erstellen.
jro
8
Beachten Sie, dass dieser Code nur aktive Verbindungen überprüft. Die Verbindungen, die keine Pakete gesendet oder empfangen haben, werden nicht aufgelistet.
JoeBilly
29
Vergleichen Sie das Ergebnis des obigen Codes mit netstat -a -b. Beachten Sie, dass LISTENINGin der keine Verbindungen vorhanden sind GetActiveTcpConnections(). Sie sollten auch einchecken System.Net.IPEndPoints[]zurückgegeben vonipGlobalProperties.GetActiveTcpListeners();
Mike de Klerk
44

Du bist am falschen Ende der Intertube. Es ist der Server, auf dem nur ein bestimmter Port geöffnet sein kann. Etwas Code:

  IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
  try {
    TcpListener tcpListener = new TcpListener(ipAddress, 666);
    tcpListener.Start();
  }
  catch (SocketException ex) {
    MessageBox.Show(ex.Message, "kaboom");
  }

Schlägt fehl mit:

Normalerweise ist nur eine Verwendung jeder Socket-Adresse (Protokoll / Netzwerkadresse / Port) zulässig.

Hans Passant
quelle
Dorthin ging ich auch. Jemand ist hier definitiv verwirrt, und es ist mir möglich.
Elch
3
Es ist möglich, dass der Client auch einen bestimmten Port benötigt, dies ist jedoch nicht üblich.
Dave Van den Eynde
@ DaveVandenEynde, das nur passieren kann, wenn der "Client" tatsächlich etwas an diesem bestimmten Port "bedient" (was ihn zumindest für diesen Port zu einem "Server" macht, soweit es TCP betrifft). - Wenn Sie eine Client-TCP-Verbindung haben, können Sie den ausgehenden Port nicht steuern. Der TCP-Stack weist Ihnen einen ausgehenden Port zu und Sie haben keine Kontrolle darüber.
BrainSlugs83
1
@ BrainSlugs83 Sie können mit Sicherheit: stackoverflow.com/questions/2869840/…
Dave Van den Eynde
Dies ist ein gültiger Code, um zu überprüfen, ob der Port frei ist. Denken Sie daran, den TcpListener zu stoppen (), falls dies erfolgreich ist (es sei denn, Sie möchten dasselbe TcpListener-Objekt verwenden, um den Port abzuhören).
Bgh
19

Wenn Sie eine TCP-Verbindung einrichten, muss das 4-Tupel (Quell-IP, Quell-Port, Ziel-IP, Ziel-Port) eindeutig sein - um sicherzustellen, dass Pakete an den richtigen Ort geliefert werden.

Auf der Serverseite gibt es eine weitere Einschränkung, dass nur ein Serverprogramm an eine eingehende Portnummer gebunden werden kann (unter der Annahme einer IP-Adresse; Multi-NIC-Server haben andere Befugnisse, aber wir müssen sie hier nicht diskutieren).

Am Serverende haben Sie also:

  • Erstellen Sie einen Socket.
  • Binden Sie diesen Socket an einen Port.
  • Hören Sie auf diesen Port.
  • Akzeptieren Sie Verbindungen an diesem Port. und es können mehrere Verbindungen eingehen (eine pro Client).

Auf der Client-Seite ist es normalerweise etwas einfacher:

  • Erstellen Sie einen Socket.
  • Öffnen Sie die Verbindung. Wenn ein Client die Verbindung öffnet, gibt er die IP-Adresse und den Port des Servers an . Es kann seinen Quellport angeben, verwendet jedoch normalerweise Null, was dazu führt, dass das System ihm automatisch einen freien Port zuweist.

Es ist nicht erforderlich, dass die Ziel-IP / der Ziel-Port eindeutig ist, da dies dazu führen würde, dass jeweils nur eine Person Google verwenden kann, und dies würde ihr Geschäftsmodell ziemlich gut zerstören.

Dies bedeutet, dass Sie sogar wundersame Dinge wie FTP mit mehreren Sitzungen ausführen können, da Sie mehrere Sitzungen eingerichtet haben, bei denen der einzige Unterschied Ihr Quellport ist, sodass Sie Chunks parallel herunterladen können. Torrents unterscheiden sich ein wenig darin, dass das Ziel jeder Sitzung normalerweise unterschiedlich ist.

Und nach all dem Waffeln (sorry) lautet die Antwort auf Ihre spezielle Frage, dass Sie keinen freien Port angeben müssen. Wenn Sie mit einem Anruf, der Ihren Quellport nicht angibt, eine Verbindung zu einem Server herstellen, wird mit ziemlicher Sicherheit Null unter der Decke verwendet, und das System gibt Ihnen eine nicht verwendete.

paxdiablo
quelle
15
TcpClient c;

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

... wie kann ich zuerst überprüfen, ob ein bestimmter Port auf meinem Computer frei ist?

Ich meine, dass es von keiner anderen Anwendung verwendet wird. Wenn eine Anwendung einen Port verwendet, können andere ihn erst verwenden, wenn er kostenlos ist. - Ali

Sie haben falsch verstanden, was hier passiert.

Die TcpClient (...) -Parameter beziehen sich auf die Server-IP und den Server-Port, zu dem Sie eine Verbindung herstellen möchten.

Der TcpClient wählt einen vorübergehenden lokalen Port aus dem verfügbaren Pool aus, um mit dem Server zu kommunizieren. Es ist nicht erforderlich, die Verfügbarkeit des lokalen Ports zu überprüfen, da dieser automatisch von der Winsock-Schicht verarbeitet wird.

Falls Sie mit dem obigen Codefragment keine Verbindung zum Server herstellen können, kann das Problem eines oder mehrere von mehreren sein. (dh Server-IP und / oder Port sind falsch, Remote-Server nicht verfügbar usw.)

Indy9000
quelle
15

Danke für diesen Tipp. Ich brauchte die gleiche Funktionalität, aber auf der Serverseite, um zu überprüfen, ob ein Port verwendet wurde, und habe ihn in diesen Code geändert.

 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;
}
Melloware
quelle
Das brauchst du nicht. Geben Sie einfach Port Null an.
Marquis von Lorne
Der Hinweis im Quellcode-Kommentar: "Dies sind die gleichen Informationen, die von der Befehlszeilenanwendung netstat bereitgestellt werden" - ist eine Lüge. Es liefert nicht die gleichen Informationen wie der Befehl netstat, liefert auch die PID der Anwendung über den Port ( -anb) und zeigt ohne Parameter die Fremdverbindung sowie den Status an.
Kraang Prime
6

danke für die antwort jro. Ich musste es für meinen Gebrauch optimieren. Ich musste überprüfen, ob ein Port abgehört wurde und nicht unbedingt aktiv war. Dafür habe ich ersetzt

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

mit

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

Ich habe das Array der Endpunkte wiederholt und überprüft, ob mein Portwert nicht gefunden wurde.

user336046
quelle
Versuchen Sie einfach, es sich selbst anzuhören. Sie brauchen nichts davon.
Marquis von Lorne
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);
}
Lernen
quelle
Ich bin derjenige, der versucht, eine Verbindung zu einer Steckdose herzustellen. Ich habe die Frage bearbeitet, um sie klarer zu machen.
Ali
Ich mag diesen Code am besten, dies öffnet wirklich eine TCP-Verbindung zu einem Socket, nur um zu sehen, ob jemand am anderen Ende zuhört oder nicht. Und ich denke, viele Leute wollen das tatsächlich, wenn sie "testen wollen, ob ein Port auf einem Remote-Host offen ist". Es gibt jedoch einen Fehler im obigen Code: Wenn (sock.Connected == true) der Port für Verbindungen geöffnet ist, lauscht dort eine serverähnliche Software. Wenn es eine SocketException mit einem 10061 ErrorCode gibt (Meldung "(0x80004005): Es konnte keine Verbindung hergestellt werden, weil der Zielcomputer sie aktiv abgelehnt hat", wird der Port geschlossen!
Csaba Toth
Es ist also umgekehrt als im Code-Snippet. Noch ein Hinweis: Wenn jemand Dns.GetHostEntry in einem solchen Test-Setup ausprobieren würde, in dem Sie virtuelle Server mit nur IP-Adressen haben, wird es eine Ausnahme geben.
Csaba Toth
3

netstat! Dies ist ein Netzwerkbefehlszeilenprogramm, das mit Windows geliefert wird. Es zeigt alle aktuell eingerichteten Verbindungen und alle Ports an, die gerade abgehört werden. Sie können dieses Programm verwenden, um zu überprüfen, aber wenn Sie dies aus dem Code heraus tun möchten, schauen Sie in den System.Net.NetworkInformation-Namespace? Es ist ein neuer Namespace ab 2.0. Da sind ein paar Leckereien. Wenn Sie jedoch die gleichen Informationen erhalten möchten, die über den Befehl netstat verfügbar sind, müssen Sie P / Invoke ausführen ...

Update: System.Net.NetworkInformation

Dieser Namespace enthält eine Reihe von Klassen, mit denen Sie Dinge über das Netzwerk herausfinden können.

Ich konnte dieses alte Stück Code nicht finden, aber ich denke, Sie können selbst etwas Ähnliches schreiben. Ein guter Anfang ist das Auschecken der IP Helper API . Google MSDN für die GetTcpTable WINAPI-Funktion und verwenden Sie P / Invoke, um aufzuzählen, bis Sie die benötigten Informationen haben.

John Leidegren
quelle
Ich verwende .NET 3.5 und kann das nicht gut machen.
Ali
Lassen Sie es mich für Sie gut machen: msdn.microsoft.com/en-us/library/…
bzlm
3

Wenn ich mich nicht sehr irre, können Sie System.Network.whatever verwenden, um dies zu überprüfen.

Dies führt jedoch immer zu einer Rennbedingung.

Die kanonische Art der Überprüfung besteht darin, diesen Port abzuhören. Wenn Sie eine Fehlermeldung erhalten, war dieser Port nicht geöffnet.

Ich denke, dies ist ein Teil dessen, warum bind () und listen () zwei separate Systemaufrufe sind.

Joshua
quelle
2

Du sagst

Ich meine, dass es von keiner anderen Anwendung verwendet wird. Wenn eine Anwendung einen Port verwendet, können andere ihn erst verwenden, wenn er kostenlos ist.

Sie können jedoch jederzeit eine Verbindung zu einem Port herstellen, während andere ihn verwenden, wenn dort etwas zuhört. Andernfalls wäre http-Port 80 ein Chaos.

Wenn dein

   c = new TcpClient(ip, port);

scheitert, dann hört dort nichts zu. Andernfalls wird eine Verbindung hergestellt, auch wenn auf einem anderen Computer / einer anderen Anwendung ein Socket für diese IP-Adresse und diesen Port geöffnet ist.

Elch
quelle
Wenn meine Anwendung versuchen zu verbinden Port 10 und eine andere Instanz meiner Anwendung Versuch 10 mit Port anschließen wieder wird es fehlschlagen , da beide Anwendungen keine Daten senden kann ein Port verwendet wird , wenn es um den Empfang von Daten - Port , dh 80 , die anders ist
Ali
Wo ist der Unterschied? Was wartet auf Port 10 für Ihre Anwendung?
Elch
Wenn dies fehlschlägt, wenn die zweite Instanz versucht, eine Verbindung herzustellen, handelt es sich um die Überwachungsanwendung und nicht um Ihre Anwendung.
Elch
2

ipGlobalProperties.GetActiveTcpConnections() gibt keine Verbindungen im Listen-Status zurück.

Der Port kann zum Abhören verwendet werden, aber wenn niemand daran angeschlossen ist, funktioniert die oben beschriebene Methode nicht.

Tevo D.
quelle
Welche Methode wurde oben beschrieben? Wie beantwortet dies die Frage?
Marquis von Lorne
2

Von den verfügbaren Häfen würde ich ausschließen:

  • aktive TCP-Verbindungen
  • aktive TCP-Listener
  • aktive UDP-Listener

Mit folgendem Import:

using System.Net.NetworkInformation;

Mit der folgenden Funktion können Sie überprüfen, ob ein Port verfügbar ist oder nicht:

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

Ich gebe Ihnen eine ähnliche Funktion für diejenigen, die VB.NET verwenden :

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

Um die genaue Frage zu beantworten, ob ich in Dotnet Core 3.1 einen freien Port finden sollte (was ich in meinen Unit-Tests benötigte), habe ich mir das ausgedacht

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

Anmerkung: Basis der Kommentar von @ user207421 über Port Null Ich suchte und fand diese und es leicht modifiziert.

CCondron
quelle
1

Beachten Sie das Zeitfenster zwischen Ihrer Überprüfung und dem Moment, in dem Sie versuchen, eine Verbindung herzustellen . Möglicherweise übernimmt ein Prozess den Port - die klassische TOCTOU . Warum versuchst du nicht einfach eine Verbindung herzustellen? Wenn dies fehlschlägt, wissen Sie, dass der Port nicht verfügbar ist.

ya23
quelle
4
TOCTOU ist YALAIHHOBIKTPBI (eine weitere lange Abkürzung, von der ich noch nichts gehört habe, aber ich kenne die Phänomene dahinter)
Csaba Toth
1

Sie müssen nicht wissen, welche Ports auf Ihrem lokalen Computer geöffnet sind, um eine Verbindung zu einem Remote-TCP-Dienst herzustellen (es sei denn, Sie möchten einen bestimmten lokalen Port verwenden, dies ist jedoch normalerweise nicht der Fall).

Jede TCP / IP-Verbindung wird durch 4 Werte identifiziert: Remote-IP, Remote-Portnummer, lokale IP, lokale Portnummer. Sie müssen jedoch nur die Remote-IP und die Remote-Portnummer kennen, um eine Verbindung herzustellen.

Wenn Sie eine TCP-Verbindung mit erstellen

TcpClient c;
c = neuer TcpClient (remote_ip, remote_port);

Ihr System weist Ihrer Verbindung automatisch eine von vielen freien lokalen Portnummern zu. Sie müssen nichts tun. Möglicherweise möchten Sie auch überprüfen, ob ein Remote-Port geöffnet ist. Aber es gibt keinen besseren Weg, als nur zu versuchen, eine Verbindung herzustellen.

Michał Piaskowski
quelle
Das ist gut, um einen Satz gegebener Steckdosen zu überprüfen. Die Frage betrifft nur einen Socket (welche Portnummer ist jedoch möglicherweise unbestimmt (?))
Csaba Toth
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;
    }
Martin.Martinsson
quelle
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.");
   }
 }
}
Yuriy Stanchev
quelle
1
Versuchen Sie beim Veröffentlichen von Code herauszufinden, warum dies die Lösung für das Problem ist. Nur Code ist möglicherweise zu wenig Information und Ihre Antwort kann übersehen werden.
Glubus
0

Überprüfen Sie den Fehlercode 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;
}
Mohsen
quelle
-2

Versuchen Sie dies. In meinem Fall war die Portnummer für das erstellte Objekt nicht verfügbar, daher habe ich mir diese ausgedacht

IPEndPoint endPoint;
int port = 1;
while (true)
{
    try
    {
        endPoint = new IPEndPoint(IPAddress.Any, port);
        break;
    }
    catch (SocketException)
    {
         port++;
    }
}
shakram02
quelle