Подтвердить что ты не робот

Как (быстро) проверить, доступен ли UNC-путь

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

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

if (fi.Exists)
//...

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

4b9b3361

Ответ 1

Как это сделать для быстрого и грязного способа проверки - запустите команду 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.

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

И вот код для этого (и 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, как указано в этом ответе на вопрос Как обеспечить подключение сетевых дисков для приложения?

Ответ 2

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

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

и это довольно быстро до сих пор...

Ответ 3

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


EDIT: Вот асинхронный сокет, который я использовал для моего проекта. Используйте этот класс для проверки определенного 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

    }
}

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

Ответ 4

Я использовал метод 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);
}

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

}

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