В C#, как проверить, доступен ли TCP-порт?

В C# для использования TcpClient или вообще для подключения к сокету как я могу сначала проверить, свободен ли определенный порт на моей машине?

подробнее: Это код, который я использую:

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

17 ответов


так как вы используете TcpClient, это означает, что вы проверяете открытые TCP-порты. Есть много хороших объектов, доступных в система.Сеть.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. Это сервер, который может иметь только один конкретный порт открыт. Код:

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

выдает:

только одно использование адреса сокета (протокол/сетевой адрес/порт) обычно разрешается.


при настройке TCP-соединения 4-кортеж (source-ip, source-port, dest-ip, dest-port) должен быть уникальным - это гарантирует, что пакеты доставляются в нужное место.

существует дополнительное ограничение на сервер сторона, что только одна серверная программа может привязываться к входящему номеру порта (при условии, что один IP-адрес; серверы multi-NIC имеют другие полномочия, но нам не нужно обсуждать их здесь).

Итак, в конце сервера, ты:

  • создать сокет.
  • свяжите этот сокет с портом.
  • прослушивает этот порт.
  • принимать соединения на этом порту. и может быть несколько подключений (по одному на клиента).

на клиентском конце обычно немного проще:

  • создать сокет.
  • открываем подключение. Когда клиент открывает соединение, он указывает ip-адрес и порт сервер. Это can укажите его исходный порт, но обычно использует ноль, что приводит к тому, что система автоматически назначает ему свободный порт.

здесь нет требование, чтобы IP/порт назначения был уникальным, так как это приведет к тому, что только один человек одновременно сможет использовать Google, и это довольно хорошо разрушит их бизнес-модель.

Это означает, что вы даже можете делать такие удивительные вещи, как многосессионный FTP, так как вы настройте несколько сеансов, где единственным отличием является исходный порт, позволяющий загружать фрагменты параллельно. Торренты немного отличаются тем, что назначение каждого сеанса обычно отличается.

и, после всего этого болтовня (извините), ответ на ваш конкретный вопрос заключается в том, что вам не нужно указать Свободный порт. Если вы подключаетесь к серверу с вызовом, который не указывает ваш исходный порт, он почти наверняка будет использовать ноль под обложками и система даст вам неиспользуемый.


TcpClient c;

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

...как я могу сначала проверить, свободен ли определенный порт на моей машине?

Я имею в виду, что он не используется другим приложением. Если приложение использует порт другие не могут использовать его, пока он не становится свободным. - Али!--3-->

вы не поняли, что здесь происходит.

TcpClient(...) параметры сервера IP и порт сервера к которому вы хотите подключиться.

TcpClient выбирает переходный локальный порт из доступного пула для связи с сервером. Нет необходимости проверять наличие локального порта, поскольку он автоматически обрабатывается слоем winsock.

Если вы не можете подключиться к серверу, используя приведенный выше фрагмент кода, проблема может быть одной или несколькими. (т. е. 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;
}

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

спасибо за ответ jro. Я должен был настроить его для моего использования. Мне нужно было проверить, прослушивается ли порт, а не обязательно активен. Для этого Я заменил

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

С

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

Я повторил массив конечных точек, проверяя, что мое значение порта не найдено.


команды netstat! Это утилита командной строки сети, которая поставляется с windows. Он показывает все текущие установленные соединения и все порты, которые в настоящее время прослушиваются. Вы можете использовать эту программу для проверки, но если вы хотите сделать это из кода, посмотрите в систему.Сеть.Пространство имен NetworkInformation? Это новое пространство имен с 2.0. Там есть кое-что вкусненькое. Но в конце концов, если вы хотите получить такую же информацию, которая доступна через команду netstat вам потребуется результат P / Invoke...

Обновление Системы.Чистая.Сведений о сети

Это пространство имен содержит множество классов, которые вы можете использовать для выяснения дела о сети.

Я не смог найти этот старый код, но я думаю, что вы можете написать что-то подобное сами. Хорошее начало, чтобы проверить IP Helper API. Google MSDN для GetTcpTable функция WINAPI и используйте P / Invoke для перечисления, пока у вас нет информации, которую вы необходимость.


скажете вы

Я имею в виду, что это не используется другое приложение. Если приложение использует порт, который другие не могут использовать пока она не станет свободной.

но вы всегда можете подключиться к порту, пока другие используют его, если что-то слушает там. В противном случае HTTP-порт 80 будет бардак.

Если

   c = new TcpClient(ip, port);

не удается, тогда ничего не слушает там. В противном случае он подключится, даже если какой-то другой машина / приложение имеет сокет, открытый для этого ip и порта.


Если я не очень ошибаюсь, вы можете использовать систему.Сеть.что бы проверить.

тем не менее, это всегда будет иметь гоночное состояние.

канонический способ проверки-попытаться прослушать этот порт. Если вы получите сообщение об ошибке, порт не был открыт.

Я думаю это часть того, почему bind () и listen () являются двумя отдельными системными вызовами.


ipGlobalProperties.GetActiveTcpConnections() не возвращает соединения в состоянии Listen.

порт может использоваться для прослушивания, но без подключения к нему описанный выше метод не будет работать.


имейте в виду, что окно времени между проверкой и моментом, когда вы пытаетесь установить соединение, какой - то процесс может занять Порт-классический TOCTOU. Почему бы тебе просто не попробовать подключить? Если это не удается, вы знаете, что порт недоступен.


вам не нужно знать, какие порты открыты на вашем локальном компьютере для подключения к какой-либо удаленной службе TCP (если вы не хотите использовать определенный локальный порт, но обычно это не так).

каждое соединение TCP / IP определяется 4 значениями: удаленный IP, номер удаленного порта, локальный IP, номер локального порта, но вам нужно только знать удаленный IP и номер удаленного порта для установления соединения.

при создании tcp-соединения с помощью

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

ваш система автоматически присвоит вашему соединению один из многих бесплатных локальных номеров портов. Тебе ничего не нужно делать. Вы также можете проверить, открыт ли удаленный порт. но нет лучшего способа сделать это, чем просто пытаться подключиться к нему.


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

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

из доступных портов я бы исключил:

  • активные 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

попробуйте это, в моем случае номер порта для созданного объекта был недоступен, поэтому я придумал это

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