C#访问远程主机资源的方法汇总和对比

由于某项目中课件资源过多,资源文件的存储采用了分布式文件系统,但是在局域网中如何访问又面临着一个问题,即局域网中访问各主机的文件同访问本机盘符下的文件是不同的,本人通过网上查询各种方案的对比,并且在实际项目中应用后对各种局域网文件访问的方法作了完整的总结

1  调用Net use DOS命令

/// <summary>
    /// 1.远程操作工具类
    /// </summary>
    public class RemoteFileTools
    {

        /// <summary>
        /// 调用Net use命令,实现远程文件操作
        /// </summary>
        /// <param name="remoteHost"></param>
        /// <param name="userName"></param>
        /// <param name="passWord"></param>
        /// <returns></returns>
        /// <remarks>
        ///  使用方法:
        ///  if (Connect("192.168.1.48", "用户名", "密码"))   
        ///  {File.Copy(@"\\192.168.1.48\共享目录\test.txt",   @"e:\\test.txt",   true);}
        /// </remarks>
        public static bool Connect(string remoteHost, string userName, string passWord)
        {
            bool Flag = true;
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = "cmd.exe";
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.RedirectStandardInput = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.CreateNoWindow = true;
            try
            {
                proc.Start();
                string command = @"net use \\" + remoteHost + " " + passWord + " " + " /user:" + userName + ">NUL";
                proc.StandardInput.WriteLine(command);
                command = "exit";
                proc.StandardInput.WriteLine(command);
                while (proc.HasExited == false)
                {
                    proc.WaitForExit(1000);
                }
                string errormsg = proc.StandardError.ReadToEnd();
                if (errormsg != "")
                    Flag = false;
                proc.StandardError.Close();
            }
            catch (Exception ex)
            {
                Flag = false;
            }
            finally
            {
                proc.Close();
                proc.Dispose();
            }
            return Flag;
        }

        public static bool Ping(string remoteHost)
        {
            bool Flag = false;
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            try
            {
                proc.StartInfo.FileName = "cmd.exe"; proc.StartInfo.UseShellExecute = false;
                proc.StartInfo.RedirectStandardInput = true; proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.RedirectStandardError = true; proc.StartInfo.CreateNoWindow = true; proc.Start();
                string dosLine = @"ping -n 1 " + remoteHost; proc.StandardInput.WriteLine(dosLine);
                proc.StandardInput.WriteLine("exit"); while (!proc.HasExited)
                {
                    proc.WaitForExit(500);
                }
                string pingResult = proc.StandardOutput.ReadToEnd(); if (pingResult.IndexOf("(0% loss)") != -1)
                {
                    Flag = true;
                }
                proc.StandardOutput.Close();
            }
            catch (Exception ex) { }
            finally
            {
                proc.Close(); proc.Dispose();
            }
            return Flag;
        }
    }



2  同上面方法有些相似之处,映射远程资源,然后访问

/// <summary>
    /// 2.	调用WNetAddConnection2、WNetAddConnection3或者NetUseAdd函数,进行磁盘映射
    /// </summary>
    public class MyMap
    {
        [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")]
        public static extern uint WNetAddConnection2(
            [In] NETRESOURCE lpNetResource,
            string lpPassword,
            string lpUsername,
            uint dwFlags);

        [DllImport("Mpr.dll")]
        public static extern uint WNetCancelConnection2(
            string lpName,
            uint dwFlags,
            bool fForce);

        [StructLayout(LayoutKind.Sequential)]
        public class NETRESOURCE
        {
            public int dwScope;
            public int dwType;
            public int dwDisplayType;
            public int dwUsage;
            public string LocalName;
            public string RemoteName;
            public string Comment;
            public string Provider;
        }

        // remoteNetworkPath format:  @"\\192.168.1.48\sharefolder"
        // localDriveName format:     @"E:"
        public static bool CreateMap(string userName, string password, string remoteNetworkPath, string localDriveName)
        {
            NETRESOURCE myNetResource = new NETRESOURCE();
            myNetResource.dwScope = 2;       //2:RESOURCE_GLOBALNET
            myNetResource.dwType = 1;        //1:RESOURCETYPE_ANY
            myNetResource.dwDisplayType = 3; //3:RESOURCEDISPLAYTYPE_GENERIC
            myNetResource.dwUsage = 1;       //1: RESOURCEUSAGE_CONNECTABLE
            myNetResource.LocalName = localDriveName;
            myNetResource.RemoteName = remoteNetworkPath;
            myNetResource.Provider = null;

            uint nret = WNetAddConnection2(myNetResource, password, userName, 0);

            if (nret == 0)
                return true;
            else
                return false;
        }

        // localDriveName format:     @"E:"
        public static bool DeleteMap(string localDriveName)
        {
            uint nret = WNetCancelConnection2(localDriveName, 1, true);

            if (nret == 0)
                return true;
            else
                return false;
        }

        public void test()
        {
            // 注意:
            // remote、local、username的格式一定要正确,否则可能出现错误
            string remote = @"\\192.168.193.90\dir";
            string local = @"P:";
            string username = @"Domain\UserName";
            string password = @"Password";
            bool ret = MyMap.CreateMap(username, password, remote, local);
            if (ret)
            {
                //do what you want:
                // ...
                //File.Copy("q:\\test.htm", "c:\\test.htm");

                MyMap.DeleteMap(local);
            }
        }
    }


使用WebClient类实现

/// <summary>
    /// 3.	使用WebClient类实现
    /// </summary>
    public class WebClint
    {
        private void Test1()
        {
            try
            {
                WebClient client = new WebClient();
                NetworkCredential cred = new NetworkCredential("username", "password", "172.16.0.222");
                client.Credentials = cred;
                client.DownloadFile("file://172.16.0.222/test/111.txt", "111.txt");
            }
            catch (Exception ex)
            {
                // 如果网络很慢,而文件又很大,这时可能有超时异常(Time out)。
            }
        }

        public void Test()
        {
            try
            {
                WebClient client = new WebClient();
                NetworkCredential cred = new NetworkCredential("username", "password", "domain");
                client.Credentials = cred;
                client.DownloadFile("file://172.16.0.222/test/111.txt", "111.txt");
            }
            catch (Exception ex)
            {
                // 如果网络很慢,而文件又很大,这时可能有超时异常(Time out)。
            }
        }
    }


通过身份模拟实现远程资源访问

/// <summary>
    /// 1.局域网内跨主机远程文件访问类,实现模拟登录,获取凭证后即可同本机路径一样访问
    /// </summary>
    /// <remarks>
    /// invoke demo,详见方法中的TestFunc:
    /// RemoteFileHelper rm = new RemoteFileHelper();
    ///  if (rm.impersonateValidUser("administrator", "\\192.168.193.50", "******"))
    ///  {System.IO.File.Copy(@"\\192.168.193.50\123\platV0.1.zip", @"E:\\f1\\platV0.1.zip", true); 
    ///  System.IO.File.Copy(@"E:\\f1\\platV0.1.zip",@"\\192.168.193.50\123\platV0.2.zip", true);}
    /// </remarks>
    public class RemoteFileHelper
    {
        // logon types
        const int LOGON32_LOGON_INTERACTIVE = 2;
        const int LOGON32_LOGON_NETWORK = 3;
        const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
        // logon providers
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_PROVIDER_WINNT50 = 3;
        const int LOGON32_PROVIDER_WINNT40 = 2;
        const int LOGON32_PROVIDER_WINNT35 = 1;

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int LogonUser(String lpszUserName,
            String lpszDomain,
            String lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int DuplicateToken(IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        private WindowsImpersonationContext impersonationContext;

        public bool impersonateValidUser(String userName, String domain, String password)
        {
            WindowsIdentity tempWindowsIdentity;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            if (RevertToSelf())
            {
                // 这里使用LOGON32_LOGON_NEW_CREDENTIALS来访问远程资源。
                // 如果要(通过模拟用户获得权限)实现服务器程序,访问本地授权数据库可
                // 以用LOGON32_LOGON_INTERACTIVE
                if (LogonUser(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS,
                    LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                {
                    if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    {
                        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                        impersonationContext = tempWindowsIdentity.Impersonate();
                        if (impersonationContext != null)
                        {
                            System.AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
                            IPrincipal pr = System.Threading.Thread.CurrentPrincipal;
                            IIdentity id = pr.Identity;
                            CloseHandle(token);
                            CloseHandle(tokenDuplicate);
                            return true;
                        }
                    }
                }
            }

            if (token != IntPtr.Zero)
                CloseHandle(token);

            if (tokenDuplicate != IntPtr.Zero)
                CloseHandle(tokenDuplicate);

            return false;
        }

        public void undoImpersonation()
        {
            impersonationContext.Undo();
        }

        public void Test()
        {
            bool isImpersonated = false;
            try
            {
                if (impersonateValidUser("UserName", "Domain", "Password"))
                {
                    isImpersonated = true;
                    File.Copy(@"\\192.168.1.48\generals\now.htm", "c:\\now.htm", true);
                }
            }
            finally
            {
                if (isImpersonated)
                    undoImpersonation();
            }
        }
    }

5  总结

1.第一种通过调用Shell命令NetUse实现,有点笨拙,且在调试时未能成功调试
2.第二种和方法一有些相似之处,映射远程资源,然后访问,需要额外的映射
3.第三种采用的是httpRequest请求,采用的是http协议,传输效率低且会有超时异常出现,所以在网络速度快、传输小文件时是可以的
4.第四种通过身份模拟实现远程资源访问,一些服务器进程就是通过这种方式运行的,也是本人项目中最终采用的方案,并有详细的注释,推荐使用


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RocChenKing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值