Em C #, como verificar se uma porta TCP está disponível?

120

Em C #, para usar um TcpClient ou geralmente para conectar a um soquete, como posso primeiro verificar se uma determinada porta está livre na minha máquina?

mais informações: Este é o código que uso:

TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
Todos
fonte
2
O que você quer dizer com "grátis" aqui? Se você tentar se conectar a ele e falhar, provavelmente não há nada ouvindo.
Jon Skeet de
2
Quero dizer que não está em uso por nenhum outro aplicativo. Se um aplicativo estiver usando uma porta, outros não poderão usá-lo até que se torne gratuito.
Ali de
Qual é o servidor ao qual você está tentando se conectar? Você o escreveu ou é um servidor existente?
luto em
3
Como já foi dito em muitas respostas, você tem tudo ao contrário. As portas locais e remotas são duas coisas totalmente diferentes. Esta resposta em particular explica bem: stackoverflow.com/questions/570098/…
bzlm

Respostas:

217

Como você está usando um TcpClient, significa que está verificando as portas TCP abertas. Existem muitos objetos bons disponíveis no namespace System.Net.NetworkInformation .

Use o IPGlobalPropertiesobjeto para chegar a uma matriz de TcpConnectionInformationobjetos, que você pode interrogar sobre o IP e a porta do endpoint.


 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
fonte
38
Lembre-se de que outro processo pode ser vinculado a essa porta durante a verificação.
Serguei
2
Como isso é relevante para a pergunta? Esta resposta trata de portas locais , não portas remotas .
bzlm
6
É relevante na medida em que responde à solicitação do OP. Apesar da diferença local / remota (concordo totalmente com você), o requisito do OP era criar um novo TcpClient com uma porta "livre".
jro,
8
Observe que este código verifica apenas as conexões ativas. As conexões que não enviaram ou receberam pacotes não serão listadas.
JoeBilly
29
Compare o resultado do código acima com netstat -a -b. Observe que as LISTENINGconexões não estão presentes no GetActiveTcpConnections(). Você também deve fazer o check-in System.Net.IPEndPoints[]devolvido poripGlobalProperties.GetActiveTcpListeners();
Mike de Klerk
44

Você está do lado errado do Intertube. É o servidor que pode ter apenas uma porta específica aberta. Algum código:

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

Falha com:

Normalmente, apenas um uso de cada endereço de soquete (protocolo / endereço de rede / porta) é permitido.

Hans Passant
fonte
É para onde eu estava indo com isso também. Alguém está definitivamente confuso aqui, e é possível que seja eu.
Moose de
3
É possível que o cliente exija uma determinada porta também, mas não é comum.
Dave Van den Eynde,
@DaveVandenEynde que só pode acontecer se o "cliente" estiver realmente "servindo" algo naquela porta em particular (tornando-o um "servidor", pelo menos para aquela porta, no que diz respeito ao TCP). - Quando você tem uma conexão TCP de cliente, não consegue controlar a porta de saída. A pilha TCP atribui a você uma porta de saída e você não tem nenhum controle sobre ela.
BrainSlugs83
1
@ BrainSlugs83 Você certamente pode: stackoverflow.com/questions/2869840/…
Dave Van den Eynde
Este é um código válido para verificar se a porta está livre. Apenas lembre-se de Stop () o TcpListener caso tenha sucesso (a menos que você pretenda usar o mesmo objeto TcpListener para começar a escutar na porta).
bgh
19

Quando você configura uma conexão TCP, a 4-tupla (ip-fonte, porta-fonte, ip-dest, porta-dest) deve ser única - isso é para garantir que os pacotes sejam entregues no lugar certo.

Há uma outra restrição no lado do servidor , de que apenas um programa de servidor pode se vincular a um número de porta de entrada (assumindo um endereço IP; os servidores multi-NIC têm outros poderes, mas não precisamos discuti-los aqui).

Então, na extremidade do servidor, você:

  • crie um soquete.
  • ligue esse soquete a uma porta.
  • escute nessa porta.
  • aceitar conexões nessa porta. e pode haver várias conexões chegando (uma por cliente).

No lado do cliente, geralmente é um pouco mais simples:

  • crie um soquete.
  • abra a conexão. Quando um cliente abre a conexão, ele especifica o endereço IP e a porta do servidor . Ele pode especificar sua porta de origem, mas geralmente usa zero, o que resulta na atribuição automática de uma porta livre pelo sistema.

Não exigência de que o IP / porta de destino seja exclusivo, pois isso resultaria em apenas uma pessoa por vez ser capaz de usar o Google, e isso destruiria muito bem seu modelo de negócios.

Isso significa que você pode até fazer coisas maravilhosas como FTP de várias sessões, já que configura várias sessões em que a única diferença é sua porta de origem, permitindo que você baixe pedaços em paralelo. Torrents são um pouco diferentes porque o destino de cada sessão geralmente é diferente.

E, depois de todo aquele waffling (desculpe), a resposta à sua pergunta específica é que você não precisa especificar uma porta livre. Se você estiver se conectando a um servidor com uma chamada que não especifica sua porta de origem, quase certamente estará usando zero nos bastidores e o sistema fornecerá uma porta não utilizada.

paxdiablo
fonte
15
TcpClient c;

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

... como posso verificar primeiro se uma determinada porta está livre em minha máquina?

Quero dizer que não está em uso por nenhum outro aplicativo. Se um aplicativo estiver usando uma porta, outros não poderão usá-lo até que se torne gratuito. - Todos

Você entendeu mal o que está acontecendo aqui.

Os parâmetros TcpClient (...) são do ip do servidor e da porta do servidor ao qual você deseja se conectar.

O TcpClient seleciona uma porta local temporária do pool disponível para se comunicar com o servidor. Não há necessidade de verificar a disponibilidade da porta local, pois ela é tratada automaticamente pela camada winsock.

Caso você não consiga se conectar ao servidor usando o fragmento de código acima, o problema pode ser um ou mais de vários. (ou seja, o ip e / ou porta do servidor está errado, o servidor remoto não está disponível, etc.)

Indy9000
fonte
15

Obrigado por esta dica. Eu precisava da mesma funcionalidade, mas no lado do servidor para verificar se uma porta estava em uso, então modifiquei para este código.

 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
fonte
Você não precisa disso. Basta especificar a porta zero.
Marquês de Lorne
A nota no comentário do código-fonte: "Esta é a mesma informação fornecida pelo aplicativo de linha de comando netstat" - é uma mentira. Ele não fornece as mesmas informações que o comando netstat também fornece o PID do aplicativo usando a porta ( -anb) e sem nenhum parâmetro mostra a conexão estrangeira, bem como o estado.
Kraang Prime
6

obrigado pela resposta jro. Eu tive que ajustá-lo para meu uso. Eu precisava verificar se uma porta estava sendo ouvida e não necessariamente ativa. Por isso eu substituí

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

com

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

Eu iterou a matriz de endpoints verificando se meu valor de porta não foi encontrado.

user336046
fonte
Apenas tente ouvir você mesmo. Você não precisa de nada disso.
Marquês de 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);
}
Aprendendo
fonte
Sou eu que estou tentando me conectar a uma tomada. Eu editei a pergunta para torná-la mais clara.
Ali de
Eu gosto mais desse código, ele realmente abre uma conexão TCP para um soquete apenas para ver se alguém está ouvindo do outro lado ou não. E eu acho que muitas pessoas realmente querem isso, quando querem "testar se uma porta está aberta em um host remoto". Porém, há um bug no código acima: if (sock.Connected == true) então a porta está aberta para conexões, algum software semelhante a um servidor está escutando lá. Se houver um SocketException com um 10061 ErrorCode (mensagem "(0x80004005): Nenhuma conexão pôde ser feita porque a máquina de destino a recusou ativamente", então a porta está fechada!
Csaba Toth
Portanto, é o contrário no trecho de código. Outra observação: se alguém tentar Dns.GetHostEntry em tal configuração de teste onde você tem servidores virtuais com apenas endereços IP, você terá uma exceção.
Csaba Toth
3

netstat! É um utilitário de linha de comando de rede que vem com o Windows. Mostra todas as conexões estabelecidas atualmente e todas as portas que estão sendo ouvidas. Você pode usar este programa para verificar, mas se quiser fazer isso a partir do código, procure no namespace System.Net.NetworkInformation? É um novo namespace a partir de 2.0. Tem algumas guloseimas lá. Mas, eventualmente, se você quiser obter o mesmo tipo de informação que está disponível através do comando netstat, você precisará obter o resultado para P / Invoke ...

Atualização: System.Net.NetworkInformation

Esse namespace contém um monte de classes que você pode usar para descobrir coisas sobre a rede.

Não consegui encontrar aquele pedaço de código antigo, mas acho que você mesmo pode escrever algo semelhante. Um bom começo é verificar a API IP Helper . Google MSDN para o função GetTcpTable WINAPI e use P / Invoke para enumerar até que você tenha as informações de que precisa.

John Leidegren
fonte
Estou usando o .NET 3.5 e não consigo entender isso.
Ali de
Permita-me esclarecer
bzlm
3

Se não me engano, você pode usar System.Network.whatever para verificar.

No entanto, isso sempre incorrerá em uma condição de corrida.

A maneira canônica de verificação é tentar escutar nessa porta. Se você receber um erro, a porta não foi aberta.

Acho que isso é parte do motivo pelo qual bind () e listen () são duas chamadas de sistema separadas.

Joshua
fonte
2

Você diz

Quero dizer que não está em uso por nenhum outro aplicativo. Se um aplicativo estiver usando uma porta, outros não poderão usá-lo até que se torne gratuito.

Mas você sempre pode se conectar a uma porta enquanto outras pessoas a estão usando, se algo estiver ouvindo lá. Caso contrário, a porta 80 http seria uma bagunça.

Se seu

   c = new TcpClient(ip, port);

falhar, então nada está ouvindo lá. Caso contrário, ele se conectará, mesmo que alguma outra máquina / aplicativo tenha um soquete aberto para aquele ip e porta.

alce
fonte
Se meu aplicativo tentar se conectar usando a porta 10 e outra instância de meu aplicativo tentar se conectar usando a porta 10 novamente, ele falhará porque ambos os aplicativos não podem enviar dados usando uma porta, quando se trata de receber dados, ou seja, porta 80 que é diferente
Ali
como é diferente? o que está escutando na porta 10 para seu aplicativo?
Moose de
se falhar quando a segunda instância tentar se conectar, é o aplicativo de escuta, não seu aplicativo.
Moose de
2

ipGlobalProperties.GetActiveTcpConnections() não retorna conexões no estado de escuta.

A porta pode ser usada para escuta, mas sem ninguém conectado a ela, o método descrito acima não funcionará.

Tevo D
fonte
Qual método descrito acima? Como isso responde à pergunta?
Marquês de Lorne
2

Das portas disponíveis, eu excluiria:

  • conexões TCP ativas
  • ouvintes TCP ativos
  • ouvintes UDP ativos

Com a seguinte importação:

using System.Net.NetworkInformation;

Você pode usar a seguinte função para verificar se uma porta está disponível ou não:

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

Eu ofereço uma função semelhante para aqueles que usam 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
Simone
fonte
2

Para responder à pergunta exata de encontrar uma porta livre (que é o que eu precisava em meus testes de unidade) no dotnet core 3.1 eu vim

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

nota: com base no comentário de @ user207421 sobre a porta zero, pesquisei e encontrei isso e modifiquei ligeiramente.

CCondron
fonte
1

Fique atento ao intervalo de tempo entre você fazer a verificação e o momento em que tenta fazer a conexão algum processo pode tomar a porta - o clássico TOCTOU . Por que você simplesmente não tenta se conectar? Se falhar, você sabe que a porta não está disponível.

ya23
fonte
4
TOCTOU é YALAIHHOBIKTPBI (Outra abreviação longa da qual não ouvi falar, mas conheço os fenômenos por trás disso)
Csaba Toth
1

Você não precisa saber quais portas estão abertas em sua máquina local para se conectar a algum serviço TCP remoto (a menos que queira usar uma porta local específica, mas geralmente esse não é o caso).

Cada conexão TCP / IP é identificada por 4 valores: IP remoto, número da porta remota, IP local, número da porta local, mas você só precisa saber o IP remoto e o número da porta remota para estabelecer uma conexão.

Quando você cria uma conexão tcp usando

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

Seu sistema atribuirá automaticamente um dos muitos números de porta local gratuitos à sua conexão. Você não precisa fazer nada. Você também pode querer verificar se uma porta remota está aberta. mas não há maneira melhor de fazer isso do que apenas tentando se conectar a ele.

Michał Piaskowski
fonte
Isso é bom para verificar um determinado conjunto de soquetes. A questão é sobre apenas um soquete (qual número de porta pode ser indeterminado embora (?))
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
fonte
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
fonte
1
Ao postar algum código, tente explicar por que ele é a solução para o problema. Apenas o código pode ser muito pouca informação e sua resposta corre o risco de ser examinada.
Glubus
0

Verifique o código de erro 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
fonte
-2

tente isso, no meu caso o número da porta para o objeto criado não estava disponível, então eu vim com este

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