Как (быстро) проверить, доступен ли путь UNC
Как я могу проверить, доступен ли путь UNC? У меня проблема в том, что проверка занимает около получаса, если общий ресурс недоступен:
var fi = new DirectoryInfo(@"\\hostname\samba-sharename\directory");
if (fi.Exists)
//...
Есть ли более быстрый способ проверить, доступна ли папка? Я использую Windows XP и C#.
8 ответов
Как это для быстрого и грязного способа проверить - запустить окна 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, как указано в этом ответе на вопрос Как обеспечить подключение сетевых дисков для приложения?
В моем проекте я использую System.IO:
if (Directory.Exists(@"\\hostname\samba-sharename\directory")) { ...
и пока довольно быстро
В моем проекте мне нужно было проверить, установлено ли соединение с сервером или нет. Я использовал сокет TCP для асинхронной проверки, может ли сервер быть достигнут или нет. Интересно, вы могли бы использовать это для проверки общего сетевого ресурса. Асинхронное 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
}
}
Изменить: Пожалуйста, не просто скопируйте / вставьте его. Постарайтесь понять код, чтобы вы могли использовать его в своих интересах, и настроить его под свои нужды.
Я закончил тем, что "обманывал" и просто пинговал хоста, что разумно, поскольку в действительности это тот случай, который я проверяю.
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();
}
}
Этот способ подходит мне больше всего из-за его скорости, простоты и надежности.
Я использовал предложенный выше метод 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);
}
Это, пожалуй, самый быстрый способ, задержкой будет общая скорость сети / доступ к диску и т. Д.
Если это вызывает задержку для пользователя, вы можете попробовать проверить это асинхронно?
Принятый ответ не сработал в моем случае, потому что диск остается «отключенным», даже если он доступен (когда моя VPN повторно подключается), пока я не получу доступ к диску.
Вместо этого это работает: сделайте один быстрый пинг IP. Например:
пинг 192.168.10.98 -n 1 -w 100
Может быть, вы должны попытаться создать папку, если она существует, она вернет ошибку, которую вы могли поймать. Там не должно быть никакого времени ожидания по умолчанию.