En C #, ¿cómo verificar si un puerto TCP está disponible?

En C # para usar un TcpClient o, en general, para conectar a un socket, ¿cómo puedo verificar primero si un determinado puerto está libre en mi máquina?

más información: este es el código que uso:

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

Dado que está utilizando un TcpClient , eso significa que está comprobando puertos TCP abiertos. Hay muchos objetos buenos disponibles en el espacio de nombres System.Net.NetworkInformation .

Utilice el objeto IPGlobalProperties para acceder a una matriz de objetos TcpConnectionInformation , que luego puede interrogar sobre la IP y el puerto del punto final.


  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. 

Estás en el lado equivocado de Intertube. Es el servidor que puede tener solo un puerto en particular abierto. Cierto 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"); } 

Falla con:

Solo se permite un uso de cada dirección de socket (protocolo / dirección de red / puerto).

Cuando configura una conexión TCP, el 4-tuple (source-ip, source-port, dest-ip, dest-port) tiene que ser único, esto es para garantizar que los paquetes se entreguen en el lugar correcto.

Existe una restricción adicional en el lado del servidor de que solo un progtwig de servidor puede vincularse a un número de puerto entrante (asumiendo una dirección IP; los servidores multi-NIC tienen otros poderes, pero no es necesario discutirlos aquí).

Entonces, al final del servidor, usted:

  • crea un socket
  • une ese socket a un puerto.
  • escucha en ese puerto.
  • aceptar conexiones en ese puerto. y puede haber múltiples conexiones entrando (una por cliente).

En el lado del cliente, generalmente es un poco más simple:

  • crea un socket
  • abre la conexión Cuando un cliente abre la conexión, especifica la dirección IP y el puerto del servidor . Puede especificar su puerto de origen, pero generalmente usa cero, lo que hace que el sistema le asigne un puerto libre automáticamente.

No hay ningún requisito de que la IP / puerto de destino sea única, ya que eso daría como resultado que solo una persona a la vez pueda usar Google, y eso destruiría muy bien su modelo comercial.

Esto significa que incluso puede hacer cosas tan maravillosas como el FTP multisesión ya que configura varias sesiones donde la única diferencia es su puerto de origen, lo que le permite descargar trozos en paralelo. Los torrents son un poco diferentes ya que el destino de cada sesión suele ser diferente.

Y, después de todo ese waffling (lo siento), la respuesta a su pregunta específica es que no necesita especificar un puerto libre. Si se está conectando a un servidor con una llamada que no especifica su puerto de origen, es casi seguro que usará cero debajo de las coberturas y el sistema le dará uno sin usar.

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

… ¿cómo puedo verificar primero si un determinado puerto está libre en mi máquina?

Quiero decir que no está siendo utilizado por ninguna otra aplicación. Si una aplicación está utilizando un puerto, otros no pueden usarlo hasta que se vuelva gratuito. Ali

Has entendido mal lo que está sucediendo aquí.

Los parámetros de TcpClient (…) son del servidor IP y del puerto del servidor al que desea conectarse.

El TcpClient selecciona un puerto local transitorio del grupo disponible para comunicarse con el servidor. No es necesario verificar la disponibilidad del puerto local, ya que la capa winsock lo maneja automáticamente.

En caso de que no pueda conectarse al servidor utilizando el fragmento de código anterior, el problema podría ser uno o más de varios. (es decir, servidor IP o puerto incorrecto, servidor remoto no disponible, etc.)

Gracias por este consejo. Necesitaba la misma funcionalidad pero en el lado del servidor para verificar si un puerto estaba en uso, así que lo modifiqué a 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; } 
 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); } 

gracias por la respuesta jro. Tuve que ajustarlo para mi uso. Necesitaba verificar si un puerto estaba siendo escuchado, y no necesariamente activo. Para esto remplacé

 TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections(); 

con

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

Repetí la matriz de puntos finales comprobando que no se encontró el valor de mi puerto.

netstat! Esa es una utilidad de línea de comandos de red que se envía con Windows. Muestra todas las conexiones establecidas actuales y todos los puertos que se están escuchando actualmente. Puede usar este progtwig para verificar, pero si desea hacer esto desde el código, busque en el espacio de nombres System.Net.NetworkInformation? Es un nuevo espacio de nombres a partir de 2.0. Hay algunos regalos allí. Pero eventualmente, si desea obtener el mismo tipo de información que está disponible a través del comando netstat, deberá dar como resultado P / Invocar …

Actualización: System.Net.NetworkInformation

Ese espacio de nombres contiene un grupo de clases que puede usar para descubrir cosas sobre la red.

No pude encontrar ese viejo código pero creo que puedes escribir algo similar tú mismo. Un buen comienzo es verificar la API de IP Helper . Google MSDN para la función GetTcpTable WINAPI y use P / Invoke para enumerar hasta que tenga la información que necesita.

Tu dices

Quiero decir que no está siendo utilizado por ninguna otra aplicación. Si una aplicación está utilizando un puerto, otros no pueden usarlo hasta que se vuelva gratuito.

Pero siempre puedes conectarte a un puerto mientras que otros lo usan si hay algo escuchando allí. De lo contrario, el puerto http 80 sería un desastre.

Si tu

  c = new TcpClient(ip, port); 

falla, entonces nada está escuchando allí. De lo contrario, se conectará, incluso si alguna otra máquina / aplicación tiene un socket abierto para esa ip y puerto.

Si no estoy muy equivocado, puede usar System.Network.whatever para verificar.

Sin embargo, esto siempre incurrirá en una condición de carrera.

La manera canónica de verificar es intentar escuchar en ese puerto. Si obtiene un error, ese puerto no estaba abierto.

Creo que esto es parte de por qué bind () y listen () son dos llamadas al sistema por separado.

ipGlobalProperties.GetActiveTcpConnections() no devuelve conexiones en Listen State.

El puerto se puede usar para escuchar, pero sin nadie conectado, el método descrito anteriormente no funcionará.

Tenga en cuenta que la ventana de tiempo entre el momento en que realiza la comprobación y el momento en que intenta realizar la conexión puede llevar algún proceso al puerto: TOCTOU clásico. ¿Por qué no tratas de conectarte? Si falla, entonces sabrá que el puerto no está disponible.

No necesita saber qué puertos están abiertos en su máquina local para conectarse a algún servicio TCP remoto (a menos que desee usar un puerto local específico, pero generalmente ese no es el caso).

Cada conexión TCP / IP está identificada por 4 valores: IP remota, número de puerto remoto, IP local, número de puerto local, pero solo necesita conocer la IP remota y el número de puerto remoto para establecer una conexión.

Cuando crea una conexión tcp usando

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

Su sistema asignará automáticamente uno de los muchos números de puerto locales gratuitos a su conexión. No necesitas hacer nada. También es posible que desee comprobar si un puerto remoto está abierto. pero no hay mejor manera de hacerlo que tratar de conectarse a él.

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

De los puertos disponibles excluiría:

  • conexiones TCP activas
  • oyentes TCP activos
  • oyentes UDP activos

Con la siguiente importación:

 using System.Net.NetworkInformation; 

Puede usar la siguiente función para verificar si un puerto está disponible o no:

 private bool isPortAvalaible(int myPort) { var avalaiblePorts = new List(); 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; } 

Le doy una función similar para aquellos que usan 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 

intente esto, en mi caso, el número de puerto para el objeto creado no estaba disponible, así que se me ocurrió esto

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