2011-03-01 35 views
31

¿Cómo puedo verificar si hay una ruta UNC disponible? tengo el problema de que el cheque tarda aproximadamente medio minuto, si la proporción es no disponibles:Cómo (rápidamente) verificar si la ruta UNC está disponible

var fi = new DirectoryInfo(@"\\hostname\samba-sharename\directory"); 

if (fi.Exists) 
//... 

¿Hay una manera más rápida para comprobar si una carpeta está disponible? Estoy usando Windows XP y C#.

+2

La única forma de saber si la carpeta dada es utilizable es intentar usarla; cualquier otra verificación es probable que dé falsos positivos –

+0

Acepto, esta es la forma más rápida. El hecho de que lleva mucho tiempo no es causado por el código In-efficient, es el tiempo de acceso al disco del servidor. –

+1

@Johnny: tengo la demora cuando el recurso compartido * no * es accesible (por lo tanto, no se puede acceder al servidor) y es bastante largo, como medio minuto. – thumbmunkeys

Respuesta

18

¿Cómo es esto de una manera rápida y sucia para comprobar - ejecutar las ventanas net use mando y analizar la salida de la línea con la ruta de red de interés (por ejemplo, \\vault2) y OK. He aquí un ejemplo de la salida:

C:\>net use 
New connections will be remembered. 

Status  Local  Remote     Network 

------------------------------------------------------------------------------- 
OK   O:  \\smarty\Data  Microsoft Windows Network 
Disconnected P:  \\dummy\Data  Microsoft Windows Network 
OK      \\vault2\vault2   Microsoft Windows Network 
The command completed successfully. 

No es una solución muy .netish, pero es muy rápido, ya veces lo que importa más :-).

Y aquí está el código para hacerlo (y LINQPad me dice que sólo se necesita 150ms, así que es agradable)

void Main() 
{ 
    bool available = QuickBestGuessAboutAccessibilityOfPath(@"\\vault2\vault2\dir1\dir2"); 
    Console.WriteLine(available); 
} 

public static bool QuickBestGuessAboutAccessibilityOfNetworkPath(string path) 
{ 
    if (string.IsNullOrEmpty(path)) return false; 
    string pathRoot = Path.GetPathRoot(path); 
    if (string.IsNullOrEmpty(pathRoot)) return false; 
    ProcessStartInfo pinfo = new ProcessStartInfo("net", "use"); 
    pinfo.CreateNoWindow = true; 
    pinfo.RedirectStandardOutput = true; 
    pinfo.UseShellExecute = false; 
    string output; 
    using (Process p = Process.Start(pinfo)) { 
     output = p.StandardOutput.ReadToEnd(); 
    } 
    foreach (string line in output.Split('\n')) 
    { 
     if (line.Contains(pathRoot) && line.Contains("OK")) 
     { 
      return true; // shareIsProbablyConnected 
     } 
    } 
    return false; 
} 

O que probablemente podría ir a la ruta de la utilización de WMI, como se alude en this answer a How to ensure network drives are connected for an application?

+2

cosas interesantes, gracias! – thumbmunkeys

+1

Probablemente debería cambiar 'line.Contains (" OK ")' to 'line.StartsWith (" OK ")' en caso de que la ruta contenga 'OK' – sparkplug

1

Eso es probablemente la forma más rápida, el retraso será la velocidad de acceso a la red en general/disco etc.

Si esto está causando un retraso para el usuario, podría intentar marcar esta forma asíncrona?

+0

Podría hacerlo asíncrono, pero el usuario todavía tendría que esperar medio minuto para el archivo. – thumbmunkeys

+1

Si navega a la misma ruta UNC en el Explorador, ¿todavía ve la misma demora? –

+0

@Mark: Sí, es el mismo retraso, lo que me indica que win xp parece tener un gran tiempo de espera al acceder a acciones de samba inexistentes. Además, la GUI del explorador se bloquea durante medio minuto cuando intenta acceder al recurso compartido (lo que es realmente malo). – thumbmunkeys

0

Quizás debería intentar crear la carpeta, si existe, devolverá un error que podría detectar. No debe haber un tiempo de espera predeterminado.

+1

Intenté eso, crear una carpeta tiene el mismo tiempo de espera largo si el recurso compartido no está disponible (Hubiera sido sorprendente si fuera de otra manera) – thumbmunkeys

3

En un proyecto mío, tuve que comprobar si se estableció o no una conexión de servidor. Utilicé un TCP Socket para verificar asincrónicamente si se podía acceder al servidor o no. Me pregunto si podría usar esto para verificar un recurso compartido de red. La conexión asincrónica de Socket TCP va tan rápido que probé la conexión 10 veces en menos de 60 milisegundos. ¿Quizás podrías jugar un poco con eso?


EDIT: Aquí es el socket asincrónico que utilicé para mi proyecto. Use esta clase para verificar cierta IP o dirección. Espero que sea de alguna utilidad para que

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net.Sockets; 
using System.Net; 
using System.Threading; 

namespace Base.BaseObjects 
{ 
    public class AsynchronousClient 
    { 
     #region Properties 

     private int _port = 0000, currentTry = 0, _buffersize, _fastpingdelay = 80; 
     private string _server = "localhost"; 
     private Socket client; 
     private static IPEndPoint remoteEP; 

     // Delegates & Events 
     public delegate void SendMessageDelegate(string message); 
     public event SendMessageDelegate SendMessageEvent; 
     public delegate void ConnectionStatusDelegate(bool connected, bool reconnect); 
     public event ConnectionStatusDelegate ConnectionStatusChanged; 

     // ManualResetEvent instances signal completion. 
     private static ManualResetEvent connectDone = new ManualResetEvent(false); 
     private static ManualResetEvent sendDone = new ManualResetEvent(false); 
     private static ManualResetEvent receiveDone = new ManualResetEvent(false); 

     /// <summary> 
     /// Port to monitor 
     /// </summary> 
     public int Port { get { return _port; } } 

     /// <summary> 
     /// Number of packages to buffer until system reports connection loss 
     /// </summary> 
     public int BufferSize { get { return _buffersize; } } 

     /// <summary> 
     /// Time in milliseconds between two pings 
     /// </summary> 
     public int FastPingDelay { get { return _fastpingdelay; } } 

     /// <summary> 
     /// Servername to connect to 
     /// </summary> 
     public string Server 
     { 
      get { return _server; } 
      set 
      { 
       _server = value; 
       // Resolve the remote endpoint for the socket. 
       try 
       { 
        IPAddress ipAddress = (IPAddress)Dns.GetHostAddresses(value)[0]; 
        remoteEP = new IPEndPoint(ipAddress, Port); 
       } 
       catch (SocketException ex) 
       { 
        SendMessage(ex.Message); 
       } 
      } 
     } 

     #endregion 

     #region Events & Delegates 

     protected void SendMessage(string message) 
     { 
      if (SendMessageEvent != null) 
       SendMessageEvent(message); 
     } 

     protected void UpdateConnectionStatus(bool connected, bool reconnect) 
     { 
      if (ConnectionStatusChanged != null) 
       ConnectionStatusChanged(connected, reconnect); 
     } 

     private void ConnectCallback(IAsyncResult ar) 
     { 
      try 
      { 
       // Retrieve the socket from the state object. 
       Socket client = (Socket)ar.AsyncState; 

       // Complete the connection. 
       client.EndConnect(ar); 

       SendMessage(String.Format("Socket connected to {0}", client.RemoteEndPoint.ToString())); 
       //UpdateConnectionStatus(true, false); 

       // Signal that the connection has been made. 
       connectDone.Set(); 
      } 
      catch (Exception e) 
      { 
       SendMessage(e.ToString()); 
       UpdateConnectionStatus(false, true); 
      } 
     } 

     #endregion 

     #region methods 

     public AsynchronousClient(int port, string server) 
     { 
      _port = port; 
      Server = server; 
      _buffersize = 10; 
      _fastpingdelay = 20; 
     } 

     public void CreateSocket() 
     { 
      try 
      { 
       StopClient(); 
      } 
      catch (Exception ex) 
      { 
       SendMessage(ex.Message); 
      } 
      finally 
      { 
       client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      } 
     } 

     public bool FastPingSocket() 
     { 
      for (currentTry = 0; currentTry <= BufferSize; currentTry++) 
      { 
       try 
       { 
        CreateSocket(); 
        client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client); 
        connectDone.WaitOne(); 
        System.Threading.Thread.Sleep(FastPingDelay); 
        client.Shutdown(SocketShutdown.Receive); 
        connectDone.WaitOne(); 
        client.Close(); 
        return true; 
       } 
       catch (SocketException ex) 
       { 
        SendMessage(ex.Message); 
       } 
       catch (ObjectDisposedException ex) 
       { 
        currentTry--; 
        SendMessage(ex.Message); 
        CreateSocket(); 
       } 
       catch (NullReferenceException ex) 
       { 
        currentTry--; 
        SendMessage(ex.Message); 
        CreateSocket(); 
       } 
       catch (ArgumentNullException ex) 
       { 
        SendMessage(ex.Message); 
        CreateSocket(); 
       } 
       catch (InvalidOperationException ex) 
       { 
        SendMessage(ex.Message); 
        CreateSocket(); 
        currentTry--; 
       } 
       finally 
       { 
        StopClient(); 
       } 
      } 
      UpdateConnectionStatus(false, true); 
      return false; 
     } 

     public void StopClient() 
     { 
      // Release the socket. 
      try 
      { 
       client.Shutdown(SocketShutdown.Both); 
       client.Close(); 
      } 
      catch (Exception) { } 
      finally 
      { 
       UpdateConnectionStatus(false, false); 
      } 
     } 

     #endregion 

    } 
} 

Editar: Por favor, no sólo tienes que copiar/pegar. Intente comprender el código para que pueda usarlo en su beneficio y afinarlo según sus necesidades.

+0

gracias por su sugerencia, verificará si el host es alcanzable y si lo es, entonces Intenta acceder al recurso compartido. – thumbmunkeys

1

utilicé el método de ping sugirió arriba y no funcionó para mí ya que estoy usando OpenDNS Aquí es una función que funcionó bien para mí:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
/// <summary> 
/// A quick method to test is the path exists 
/// </summary> 
/// <param name="s"></param> 
/// <param name="timeOutMs"></param> 
/// <returns></returns> 
public static bool CheckPathExists(string s, int timeOutMs = 120) { 
    if (s.StartsWith(@"\\")) { 
     Uri uri = new Uri(s); 
     if (uri.Segments.Length == 0 || string.IsNullOrWhiteSpace(uri.Host)) 
      return false; 
     if (uri.Host != Dns.GetHostName()) { 
      WebRequest request; 
      WebResponse response; 
      request = WebRequest.Create(uri); 
      request.Method = "HEAD"; 
      request.Timeout = timeOutMs; 
      try { 
       response = request.GetResponse(); 
      } catch (Exception ex) { 
       return false; 
      } 
      return response.ContentLength > 0; 

      // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
      // Do a Ping to see if the server is there 
      // This method doesn't work well using OPenDNS since it always succeeds 
      // regardless if the IP is a valid or not 
      // OpenDns always maps every host to an IP. If the host is not valid the 
      // OpenDNS will map it to 67.215.65.132 
      /* Example: 
       C:\>ping xxx 

       Pinging xxx.RT-AC66R [67.215.65.132] with 32 bytes of data: 
       Reply from 67.215.65.132: bytes=32 time=24ms TTL=55 
       */ 

      //Ping pingSender = new Ping(); 
      //PingOptions options = new PingOptions(); 
      // Use the default Ttl value which is 128, 
      // but change the fragmentation behavior. 
      //options.DontFragment = true; 

      // Create a buffer of 32 bytes of data to be transmitted. 
      //string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 
      //byte[] buffer = Encoding.ASCII.GetBytes(data); 
      //int timeout = 120; 
      //PingReply reply = pingSender.Send(uri.Host, timeout, buffer, options); 
      //if (reply == null || reply.Status != IPStatus.Success) 
      // return false; 
     } 
    } 
    return File.Exists(s); 
} 
5

En mi proyecto que utilice el System.IO:

if (Directory.Exists(@"\\hostname\samba-sharename\directory")) { ... 

y es bastante rápido hasta ahora ...

+0

¿lo ha intentado cuando el recurso compartido no está disponible? – thumbmunkeys

+1

Sí, esto es para probar la existencia y la disponibilidad ... Tal vez hay una clase de tiempo de espera para configurar desde el administrador de la red cuando no está disponible, y esa sería la razón por la que tiene que esperar 30 segundos ...? – fasa

Cuestiones relacionadas