Как (быстро) проверить, доступен ли путь UNC - PullRequest
34 голосов
/ 01 марта 2011

Как я могу проверить, доступен ли путь UNC? У меня проблема в том, что проверка занимает около получаса, если доля не доступна:

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

if (fi.Exists)
//...

Есть ли более быстрый способ проверить, доступна ли папка? Я использую Windows XP и C #.

Ответы [ 7 ]

21 голосов
/ 03 августа 2012

Как это сделать для быстрого и грязного способа проверки - запустите команду windows net use и проанализируйте выходные данные для строки с интересующим сетевым путем (например, \\vault2) и OK.Вот пример вывода:

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.

Это не очень .netish решение, но оно очень быстрое, а иногда и имеет значение больше: -).

А вот код, который нужно сделатьэто (и LINQPad говорит мне, что это займет всего 150 мс , так что это хорошо)

void Main()
{
    bool available = QuickBestGuessAboutAccessibilityOfNetworkPath(@"\\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;
}

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

7 голосов
/ 28 сентября 2016

В моем проекте я использую System.IO:

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

и пока довольно быстро ...

3 голосов
/ 01 марта 2011

В моем проекте мне нужно было проверить, установлено ли соединение с сервером или нет.Я использовал TCP Socket для асинхронной проверки, может ли сервер быть достигнут или нет.Интересно, вы могли бы использовать это для проверки общего сетевого ресурса.Асинхронное TCP-соединение происходит так быстро, что я тестировал соединение 10 раз за 60 миллисекунд.Может быть, вы могли бы немного поиграть с этим?


РЕДАКТИРОВАТЬ: Вот асинхронный сокет, который я использовал для своего проекта.Используйте этот класс для проверки определенного IP-адреса или адреса.Надеюсь, что это вам пригодится

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

    }
}

Редактировать: Пожалуйста, не копируйте и не вставляйте его.Постарайтесь понять код, чтобы вы могли использовать его в своих интересах, и настроить его под свои нужды.

2 голосов
/ 13 декабря 2013

Я использовал метод ping, предложенный выше, и он не работал для меня, так как я использую OpenDNS Вот функция, которая хорошо сработала для меня:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// <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);
}
1 голос
/ 14 декабря 2018

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

private bool HostExists(string PCName)
{
    Ping pinger = new Ping();

    try
    {
        PingReply reply = pinger.Send(PCName);
        return reply.Status == IPStatus.Success;
    }
    catch
    {
        return false;
    }
    finally
    {
        pinger.Dispose();
    }

}

Этот способ подходит мне больше всего благодаря своей скорости, простоте и надежности.

1 голос
/ 01 марта 2011

Это, пожалуй, самый быстрый способ, задержкой будет общая скорость сети / доступ к диску и т. Д.

Если это вызывает задержку для пользователя, вы можете попробовать проверить это асинхронно?

0 голосов
/ 01 марта 2011

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

...