如何(快速)检查 UNC 路径是不是可用

Posted

技术标签:

【中文标题】如何(快速)检查 UNC 路径是不是可用【英文标题】:How to (quickly) check if UNC Path is available如何(快速)检查 UNC 路径是否可用 【发布时间】:2011-03-01 09:32:27 【问题描述】:

如何检查 UNC 路径是否可用? 如果共享可用,我的问题是检查大约需要半分钟:

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

if (fi.Exists)
//...

有没有更快的方法来检查文件夹是否可用? 我使用的是 Windows XP 和 C#。

【问题讨论】:

知道给定文件夹是否可用的唯一方法是尝试使用它 - 任何其他检查都可能给出误报 我同意,这是最快的方法。耗时长并不是代码效率低造成的,而是服务器的磁盘访问时间。 @Johnny:当共享 not 可访问(因此服务器无法访问)并且很长,比如半分钟时,我有延迟。 这是默认的超时机制。 @DanielHilgarth - 有什么办法可以减少检查时的超时时间吗? 【参考方案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.

这不是一个非常 .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 的路线,正如this answer 到How to ensure network drives are connected for an application? 中提到的那样

【讨论】:

如果路径包含“OK”,可能应该将line.Contains("OK") 更改为line.StartsWith("OK") 这是一个出色的解决方案,适用于映射驱动器。知道如何将此功能用于共享但不一定映射的网络路径吗? 仅供参考:如果此代码将以管理员身份运行,而映射驱动器处于用户级别,您将获得 New connections will be remembered. There are no entries in the list. 这需要使用net use 命令映射每次网络位置,但对于未映射的直接路径 \\10.10.10.10\foo\bar 这将不起作用:(【参考方案2】:

在我的项目中,我使用 System.IO:

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

到目前为止速度非常快......

【讨论】:

是的,这是为了测试存在性和可用性...也许网络管理员在不可用时设置了某种超时时间,这就是您必须等待 30 秒的原因。 .?【参考方案3】:

在我的一个项目中,我必须检查是否建立了服务器连接。我使用 TCP Socket 来异步检查是否可以访问服务器。我想知道您是否可以使用它来检查网络共享。异步 TCP 套接字连接速度非常快,我在 60 毫秒内对连接进行了 10 次测试。也许你可以玩弄一下?


编辑:这是我用于我的项目的异步套接字。使用此类检查某个 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 主机,这是合理的,因为我正在检查的实际情况就是这样。

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


这种方式最适合我,因为它速度快、简单且可靠。

【讨论】:

注意:这里使用“使用 System.Net.NetworkInformation;” 注意:如果在主机之间或主机上的防火墙上禁用了 ICMP,这将不起作用。【参考方案5】:

我使用了上面建议的 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);

【讨论】:

【参考方案6】:

这可能是最快的方法,延迟将是一般的网络速度/磁盘访问等。

如果这导致用户延迟,您可以尝试异步检查吗?

【讨论】:

我可以让它异步,但用户仍然需要等待半分钟才能获得文件。 如果您在资源管理器中导航到相同的 UNC 路径,您是否仍然看到相同的延迟? 我认为这种情况下的延迟是一个不争的事实,它只是如何优雅地呈现给用户。 @pivot:是的,这需要很长时间。不仅在 Windows XP 中如此;所有版本的 Windows 都有类似的超时。可能有一种方法可以更改它,但它不会对您的用户有任何帮助。 Mark 建议用漂亮的 GUI 覆盖它是您唯一的选择。 Explorer 甚至都懒得这么做。如果你充分分散了用户的注意力(比如使用进度条),他们可能不会在意。尤其是如果您的应用不必重复(它不应该)这样做。 @pivot:根据您的原始问题,不,您不能(也不应该)提前检查驱动器是否可用。这会导致不可避免的竞争条件,而且意义不大。正如其他人所建议的那样,最好尝试使用驱动器并检测故障。无论如何,您都必须编写该代码。【参考方案7】:

也许你应该尝试创建文件夹,如果它确实存在,它会返回一个你可以捕捉到的错误。应该没有默认超时。

【讨论】:

我试过了,如果共享不可用,创建文件夹的超时时间相同(否则会令人惊讶)

以上是关于如何(快速)检查 UNC 路径是不是可用的主要内容,如果未能解决你的问题,请参考以下文章

检查共享路径在 pc 中是不是可用

如何检查远程IP和端口是不是可用?

android – 如何检查 webview 是不是可用?

如何修复“代码应明确检查权限是不是可用”错误

如何检查 C# 中的库 (dll) 是不是可用?

如何在android中检查当前的互联网连接是不是可用