zoukankan      html  css  js  c++  java
  • C#访问远程主机资源的方法,多种方式

    最近要实现访问远程主机的共享目录中的一个文件。遇到了权限问题。google了一下,找到了几种解决方法,记录如下:

    一、调用Net use命令

            // 使用方法:
            //if (Connect("192.168.1.48", "用户名", "密码"))   
            //{
            //    File.Copy(@"\192.168.1.48共享目录 est.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.48sharefolder"
            // 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.48generals";
                string local = @"P:";
                string username = @"DomainUserName";
                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);
                    ... ...



    四、角色模拟

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    using System.IO;

    namespace Test
    {
        public class Test
        {
            // 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 TestFunc()
            {
                bool isImpersonated = false;
                try
                {
                    if (impersonateValidUser("UserName", "Domain", "Password"))
                    {
                        isImpersonated = true;
                        //do what you want now, as the special user
                        // ...
                        File.Copy(@"\192.168.1.48generals ow.htm", "c:\now.htm", true);
                    }
                }
                finally
                {
                    if (isImpersonated)
                        undoImpersonation();
                }
            }
        }
    }


    五、比较

    方法一通过调用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.48generals";
                string local = @"P:";
                string username = @"DomainUserName";
                string password = @"Password";

        如果@"\192.168.1.48generals"变成@"\192.168.1.48generals”就会出错;
        如果是域中的用户,那么把@"DomainUserName"变成@"UserName"就会出错。

  • 相关阅读:
    包装类型
    int 和 Integer 有什么区别
    final finally finalize区别
    java关键字final 有什么用?
    String和StringBuffer、StringBuilder的区别是什么?
    String 类的常用方法都有那些?
    Vue官网教程-计算属性和监听器
    Vue官网教程-模板语法
    Vue官网教程-实例
    Vue官网教程-介绍
  • 原文地址:https://www.cnblogs.com/goody9807/p/3179516.html
Copyright © 2011-2022 走看看