如何(快速)检查 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 路径是不是可用的主要内容,如果未能解决你的问题,请参考以下文章