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

120

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

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

TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
Али
источник
2
Что вы здесь имеете в виду под словом "бесплатно"? Если вы попытаетесь подключиться к нему и потерпите неудачу, это, вероятно, означает, что ничего не слушает.
Джон Скит,
2
Я имею в виду, что он не используется другими приложениями. Если приложение использует порт, другие не могут его использовать, пока он не станет бесплатным.
Али
К какому серверу вы пытаетесь подключиться? Вы его написали или это уже существующий сервер?
горевать
3
Как было сказано во многих ответах, у вас все наоборот. Локальные порты и удаленные порты - это совершенно разные вещи. Этот ответ, в частности, хорошо это объясняет: stackoverflow.com/questions/570098/…
bzlm

Ответы:

218

Поскольку вы используете a 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.
JRO
источник
38
Имейте в виду, что во время проверки к этому порту может привязаться другой процесс.
Сергей
2
Как это относится к вопросу? Этот ответ касается локальных портов, а не удаленных .
bzlm
6
Это актуально в том смысле, что отвечает на запрос ОП. Несмотря на разницу между локальным и удаленным (полностью согласен с вами), OP требовал создать новый TcpClient с портом, который является «свободным».
jro
8
Обратите внимание, что этот код проверяет только активные соединения. Соединения, которые не отправили или не получили пакеты, не будут перечислены.
JoeBilly
29
Сравните результат кода выше с netstat -a -b. Обратите внимание, что LISTENINGподключения отсутствуют в файле GetActiveTcpConnections(). Вам также следует пройти регистрацию, System.Net.IPEndPoints[]возвращеннуюipGlobalProperties.GetActiveTcpListeners();
Майк де Клерк,
44

Вы не на том конце 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");
  }

Не работает с:

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

Ганс Пассан
источник
Вот куда я и собирался. Кто-то здесь точно запутался, и возможно это я.
Moose
3
Возможно, что клиенту тоже нужен определенный порт, но это нечасто.
Дэйв Ван ден Эйнде
@DaveVandenEynde, что может произойти только в том случае, если «клиент» на самом деле «обслуживает» что-то на этом конкретном порту (что делает его «сервером», по крайней мере, для этого порта, что касается TCP). - Когда у вас есть клиентское TCP-соединение, вы не можете контролировать исходящий порт. Стек TCP назначает вам исходящий порт, и вы не можете его контролировать.
BrainSlugs83
1
@ BrainSlugs83 Скорее всего, сможете: stackoverflow.com/questions/2869840/…
Дэйв Ван ден Эйнде,
Это допустимый фрагмент кода для проверки, свободен ли порт. Просто не забудьте остановить () TcpListener в случае успеха (если вы не собираетесь использовать тот же объект TcpListener для начала прослушивания порта).
bgh 08
19

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

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

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

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

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

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

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

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

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

paxdiablo
источник
15
TcpClient c;

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

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

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

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

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

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

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

Indy9000
источник
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;
}
Melloware
источник
Тебе это не нужно. Просто укажите нулевой порт.
Маркиз Лорн,
Примечание в комментарии к исходному коду: «Это та же информация, которую предоставляет приложение командной строки netstat» - ложь. Он не предоставляет ту же информацию, что и команда netstat, также предоставляет PID приложения с использованием port ( -anb) и без каких-либо параметров показывает внешнее соединение, а также состояние.
Kraang Prime
6

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

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

с участием

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

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

user336046
источник
Попробуйте сами послушать. Вам это не нужно.
Маркиз Лорн,
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), то порт открыт для подключений, там прослушивает какое-то серверное программное обеспечение. Если существует SocketException с кодом ошибки 10061 (сообщение «(0x80004005): Невозможно установить соединение, потому что целевая машина активно отказалась от него», то порт закрывается!
Чаба Тот,
Так что во фрагменте кода все наоборот. Еще одно замечание: если кто-то попробует Dns.GetHostEntry в такой тестовой настройке, где у вас есть виртуальные серверы только с IP-адресами, у вас будет исключение.
Csaba Toth
3

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

Обновление: System.Net.NetworkInformation

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

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

Джон Лейдегрен
источник
Я использую .NET 3.5 и не могу этого добиться.
Али
Позвольте мне оштрафовать вас: msdn.microsoft.com/en-us/library/…
bzlm
3

Если я не сильно ошибаюсь, вы можете использовать System.Network.whatever для проверки.

Однако это всегда будет вызывать состояние гонки.

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

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

Джошуа
источник
2

Ты говоришь

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

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

Если ваш

   c = new TcpClient(ip, port);

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

лось
источник
Если мое приложение попытается подключиться через порт 10, а другой экземпляр моего приложения попытается снова подключиться через порт 10, это не удастся, потому что оба приложения не могут отправлять данные через один порт, когда дело доходит до получения данных, то есть порт 80, который отличается
Али
чем он отличается? что прослушивает порт 10 для вашего приложения?
Moose
если он терпит неудачу, когда второй экземпляр пытается подключиться, это прослушивающее приложение, а не ваше приложение.
Moose
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;
    }

примечание: основываясь на комментарии @ user207421 о нулевом порте, я искал и нашел его и немного изменил его.

CCondron
источник
1

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

ya23
источник
4
TOCTOU - это YALAIHHOBIKTPBI (еще одно длинное сокращение, о котором я не слышал, но я знаю, что за ним стоит)
Csaba Toth
1

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

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

Когда вы создаете TCP-соединение с помощью

TcpClient c;
c = новый TcpClient (remote_ip, remote_port);

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

Михал Пясковский
источник
Это хорошо для проверки набора заданных сокетов. Вопрос только в одном сокете (хотя номер порта может быть не определен (?))
Чаба Тот
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
источник
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 08
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++;
    }
}
shakram02
источник