C#訪問遠程主機資源的多種方法分享

來源:互聯網
上載者:User
最近要實現訪問遠程主機的共用目錄中的一個檔案。遇到了許可權問題。google了一下,找到了幾種解決方案,記錄如下:
一、調用Net use命令

 // 使用方法:        //if (Connect("192.168.1.48", "使用者名稱", "密碼"))           //{        //    File.Copy(@"\\192.168.1.48\共用目錄\test.txt",   @"e:\\test.txt",   true);           //}        public bool Connect(string remoteHost, string userName, string passWord)        {            bool Flag = true;            Process proc = new 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;        }

二、調用WNetAddConnection2、WNetAddConnection3或者NetUseAdd函數,進行磁碟映射。

using System;using System.Collections.Generic;using System.Text;       using System.Runtime.InteropServices;namespace WindowsApplication1{    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.1.48\generals";            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類

由於WebClient類可以上傳下載檔案,並且支援以http:、https:和file:開頭的URI,所以可以用WebClient類來傳輸檔案。
添加System.Net命名空間後使用如下代碼下載檔案:

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 Test2()        {            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)。            }        }

類似的還可以試試WebRequest、FileWebRequest等:

 WebRequest req = WebRequest.Create("file://138.12.12.14/generals/test.htm");                NetworkCredential cred = new NetworkCredential("username", "password", "IP");                req.Credentials = cred;                WebResponse response = req.GetResponse();                Stream strm = response.GetResponseStream();                StreamReader r = new StreamReader(strm);                ... ...

四、角色類比

/// <summary>    /// 身份類比實現遠端資源訪問    /// </summary>    public class FileImpersonation    {        // 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;        /// <summary>        /// 身份類比        /// </summary>        /// <param name="userName">獨立伺服器用IP,域環境就用網域名稱</param>        /// <param name="domain"></param>        /// <param name="password"></param>        /// <returns></returns>        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)                        {                            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;        }        /// <summary>        /// 取消類比身份        /// </summary>        public void undoImpersonation()        {            impersonationContext.Undo();        }        /// <summary>        ///         /// </summary>        /// <param name="domain">獨立伺服器用IP,域環境就用網域名稱</param>        /// <param name="username"></param>        /// <param name="password"></param>        /// <param name="act">需要執行的操作</param>        public void ImpersonateFunc(string username, string domain, string password, Action act)        {            bool isImpersonated = false;            try            {                if (impersonateValidUser(username, domain, password))                {                    isImpersonated = true;                    //File.Copy(@"\\192.168.1.48\generals\now.htm", "c:\\now.htm", true);                    act();                }            }            catch (Exception ex)            {                Console.WriteLine(ex.ToString());            }            finally            {                if (isImpersonated)                    undoImpersonation();            }        }        //    } FileImpersonation imp = new FileImpersonation();            imp.ImpersonateFunc("Administrator", "192.168.0.125", "xxxx", () =>            {                var source = new DirectoryInfo(@"D:\HR");                string targetFolder = @"\\192.168.0.125\d$\HR";                if (!Directory.Exists(targetFolder))                {                    Directory.CreateDirectory(targetFolder);                }                foreach (FileInfo item in source.GetFiles())                {                    string targertFile = Path.Combine(targetFolder, item.Name);                    File.Copy(item.FullName, targertFile, true);                }            });

五、比較

方法一通過調用Shell命令Net Use實現,有點笨拙。
方法二和方法一有些相似之處。映射遠端資源,然後訪問。
方法三由於會有逾時異常出現,所以在網路速度快、傳輸小檔案時是可以的。
方法四通過身份類比實現遠端資源訪問。一些伺服器處理序就是通過這種方式啟動並執行。這種方法也是我的最愛。

六、要注意的地方

關於這幾種方法,google後都可以找到一些文章。但是等到自己實際測試時,有時會出現各種小錯誤,
這些錯誤基本來源於兩方面:

1、函數的參數選擇有問題,和自己的環境不相符。
比如

public static extern int LogonUser(String lpszUserName,            String lpszDomain,            String lpszPassword,            int dwLogonType,            int dwLogonProvider,            ref IntPtr phToken);

中的dwLogonType,要訪問遠端資源就要用LOGON32_LOGON_NEW_CREDENTIALS,
要類比本機使用者就要用LOGON32_LOGON_INTERACTIVE。

2、函數的參數格式有問題。
a、比如

 public static extern int LogonUser(String lpszUserName,            String lpszDomain,            String lpszPassword,            int dwLogonType,            int dwLogonProvider,            ref IntPtr phToken);

中的lpszUserName、lpszDomain、lpszPassword就要寫清楚。

我就在這遇到過問題,第一次測試時,遠程伺服器就是一台獨立的檔案伺服器,這是我的調用方式:
LogonUser("myname", "192.168.1.48", "password", LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_DEFAULT, ref token);

第二次測試時,遠程伺服器是域MyDomain中的一個成員伺服器,提供檔案服務。這時代碼就應該是:

 LogonUser("myname", "MyDomain", "password", LOGON32_LOGON_NEW_CREDENTIALS,                    LOGON32_PROVIDER_DEFAULT, ref token);

注意,代碼中是MyDomain而不是IP地址。

b、再如:
參考上面代碼

 string remote = @"\\192.168.1.48\generals";            string local = @"P:";            string username = @"Domain\UserName";            string password = @"Password";

如果@"\\192.168.1.48\generals"變成@"\\192.168.1.48\generals\”就會出錯;
如果是域中的使用者,那麼把@"Domain\UserName"變成@"UserName"就會出錯。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.