web-dev-qa-db-fra.com

En C #, comment vérifier si un TCP le port est disponible?

En C #, utiliser un TcpClient ou généralement se connecter à un socket, comment puis-je d'abord vérifier si un certain port est libre sur ma machine?

plus d'infos: C'est le code que j'utilise:

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

Puisque vous utilisez une TcpClient, cela signifie que vous vérifiez les ports ouverts TCP. Il y a beaucoup de bons objets disponibles dans System.Net.NetworkInformation namespace.

Utilisez l'objet IPGlobalProperties pour accéder à un tableau d'objets TcpConnectionInformation, que vous pouvez ensuite interroger à propos de l'adresse IP et du port du terminal.


 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

Vous êtes du mauvais côté de l'Intertube. C'est le serveur qui ne peut avoir qu'un seul port ouvert. Un 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");
  }

Échoue avec:

Une seule utilisation de chaque adresse de socket (protocole/adresse réseau/port) est normalement autorisée.

39
Hans Passant

Lorsque vous configurez une connexion TCP, le 4-Tuple (source-ip, source-port, dest-ip, dest-port) doit être unique - ceci afin de garantir que les paquets sont livrés au bon endroit.

Le côté server est soumis à une restriction supplémentaire selon laquelle un seul programme serveur peut se lier à un numéro de port entrant (en supposant une adresse IP unique; les serveurs multi-NIC ont d'autres pouvoirs, mais nous n'avons pas besoin de les discuter ici).

Donc, côté serveur, vous:

  • créer une socket.
  • lier cette prise à un port.
  • écoute sur ce port.
  • accepter les connexions sur ce port . et il peut y avoir plusieurs connexions entrantes (une par client).

Du côté du client, c'est généralement un peu plus simple:

  • créer une socket.
  • ouvrir la connexion . Lorsqu'un client ouvre la connexion, il spécifie l'adresse IP et le port du server . Il peut spécifier son port source mais utilise généralement zéro, ce qui a pour conséquence que le système lui attribue automatiquement un port libre.

Il est non obligatoire que l’adresse IP/le port de destination soit unique, car cela ne ferait en sorte qu’une seule personne à la fois puisse utiliser Google, ce qui détruirait plutôt son modèle commercial.

Cela signifie que vous pouvez même faire des choses merveilleuses comme le FTP multi-sessions puisque vous configurez plusieurs sessions où la seule différence est votre port source, vous permettant de télécharger des morceaux en parallèle. Les torrents sont un peu différents en ce sens que la destination de chaque session est généralement différente.

Et, après tout ce brouhaha (désolé), la réponse à votre question spécifique est qu'il n'est pas nécessaire de spécifier un port libre. Si vous vous connectez à un serveur avec un appel qui ne spécifie pas votre port source, il utilisera certainement le zéro sous couverture et le système vous en donnera un non utilisé.

19
paxdiablo
TcpClient c;

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

... comment puis-je d'abord vérifier si un certain port est libre sur ma machine?

Je veux dire qu'il n'est utilisé par aucune autre application. Si une application utilise un port, les autres utilisateurs ne peuvent pas l'utiliser tant qu'il n'est pas gratuit. - ALi

Vous avez mal compris ce qui se passe ici. 

Les paramètres de TcpClient (...) sont ceux du serveur ip et du port du serveur auquel vous souhaitez vous connecter. 

TcpClient sélectionne un port local transitoire dans le pool disponible pour communiquer avec le serveur. Il n'est pas nécessaire de vérifier la disponibilité du port local car celui-ci est automatiquement géré par la couche winsock.

Si vous ne pouvez pas vous connecter au serveur en utilisant le fragment de code ci-dessus, le problème peut être lié à un ou plusieurs problèmes. (c'est-à-dire que l'adresse IP et/ou le port du serveur sont incorrects, le serveur distant n'est pas disponible, etc.)

15
Indy9000

Merci pour ce conseil. J'avais besoin de la même fonctionnalité mais côté serveur pour vérifier si un port était utilisé, je l'ai donc modifié pour ce code.

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

merci pour la réponse jro. Je devais le modifier pour mon usage. Je devais vérifier si un port était écouté et pas nécessairement actif. Pour cela j'ai remplacé 

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

avec 

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

J'ai itéré le tableau des noeuds finaux en vérifiant que la valeur de mon port était introuvable.

6
user336046

netstat! C'est un utilitaire de ligne de commande réseau livré avec Windows. Il montre toutes les connexions établies actuelles et tous les ports en cours d'écoute. Vous pouvez utiliser ce programme pour vérifier, mais si vous voulez le faire à partir de code, consultez l'espace de noms System.Net.NetworkInformation? C'est un nouvel espace de noms à partir de 2.0. Il y a des bonbons là-bas. Mais finalement, si vous voulez obtenir le même type d’information disponible par le biais de la commande netstat, vous devez obtenir P/Invoke ...

Mise à jour: System.Net.NetworkInformation

Cet espace de noms contient un ensemble de classes que vous pouvez utiliser pour comprendre le réseau.

Je ne pouvais pas trouver cette vieille pièce de code, mais je pense que vous pouvez écrire quelque chose de similaire vous-même. Un bon début est de vérifier le API IP Helper . Google MSDN pour la fonction GetTcpTable WINAPI et utilisez P/Invoke pour énumérer jusqu'à obtenir les informations dont vous avez besoin.

3
John Leidegren

ipGlobalProperties.GetActiveTcpConnections() ne renvoie pas de connexions dans l'état d'écoute.

Le port peut être utilisé pour l'écoute, mais sans personne connectée, la méthode décrite ci-dessus ne fonctionnera pas.

2
Broken Pipe

Si je ne me trompe pas vraiment, vous pouvez utiliser System.Network.wwhat pour vérifier.

Cependant, cela entraînera toujours une condition de concurrence.

La manière canonique de vérifier est d'essayer d'écouter sur ce port. Si vous obtenez une erreur, ce port n'était pas ouvert.

Je pense cela explique en partie pourquoi bind () et listen () sont deux appels système distincts.

2
Joshua

Vous dites 

Je veux dire qu'il n'est pas utilisé par aucun autre application. Si une application utilise un port que d'autres ne peuvent pas utiliser jusqu'à ce qu'il devienne libre.

Mais vous pouvez toujours vous connecter à un port pendant que d'autres l'utilisent si quelque chose y écoute. Sinon, le port HTTP 80 serait un gâchis.

Si ton 

   c = new TcpClient(ip, port);

échoue, alors rien n'y écoute. Sinon, il se connectera, même si une autre machine/application possède un socket ouvert à cette adresse IP et ce port.

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
Martin.Martinsson

Sachez que la fenêtre temporelle entre la vérification et le moment où vous essayez d'établir une connexion peut prendre le port - classique TOCTOU . Pourquoi n'essayez-vous pas simplement de vous connecter? Si cela échoue, vous savez que le port n'est pas disponible.

1
ya23

Je exclurais des ports disponibles:

  • connexions actives TCP 
  • auditeurs TCP actifs 
  • auditeurs UDP actifs

Avec l'importation suivante:

using System.Net.NetworkInformation;

Vous pouvez utiliser la fonction suivante pour vérifier si un port est disponible ou non:

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

Je vous donne une fonction similaire pour ceux qui utilisent 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
1
Simone

Vous n'avez pas besoin de savoir quels ports sont ouverts sur votre ordinateur local pour vous connecter à un service distant TCP (sauf si vous souhaitez utiliser un port local spécifique, mais ce n'est généralement pas le cas).

Chaque connexion TCP/IP est identifiée par 4 valeurs: adresse IP distante, numéro de port distant, adresse IP locale, numéro de port local, mais vous devez uniquement connaître l'adresse IP distante et le numéro de port distant pour établir une connexion. 

Lorsque vous créez une connexion TCP en utilisant

 TcpClient c; 
 C = new TcpClient (remote_ip, remote_port); 

Votre système attribuera automatiquement l'un des nombreux numéros de port locaux gratuits à votre connexion. Vous n'avez rien à faire .. Vous pouvez également vérifier si un port distant est ouvert. mais il n'y a pas de meilleur moyen de le faire que d'essayer de s'y connecter.

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

Recherchez le code d'erreur 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