C# 如何确定哪个IIS Express实例正在使用端口?

C# 如何确定哪个IIS Express实例正在使用端口?,c#,iis,iis-express,C#,Iis,Iis Express,我想以编程方式终止正在运行的占用特定端口的IIS实例,但似乎无法确定哪个IIS实例正在使用特定端口 netstat.exe只是显示进程具有PID 4,但这是系统进程。“netsh http show urlacl”根本不显示占用的端口 IIS Express托盘程序不知怎么知道这一点。当我尝试在端口被占用的情况下启动另一个IIS Express实例时,会出现以下错误: 进程“IIS Express”(进程ID“10632”)已在使用端口“40000” 有人知道我如何获取这些信息吗?您可以运行下面

我想以编程方式终止正在运行的占用特定端口的IIS实例,但似乎无法确定哪个IIS实例正在使用特定端口

netstat.exe只是显示进程具有PID 4,但这是系统进程。“netsh http show urlacl”根本不显示占用的端口

IIS Express托盘程序不知怎么知道这一点。当我尝试在端口被占用的情况下启动另一个IIS Express实例时,会出现以下错误:
进程“IIS Express”(进程ID“10632”)已在使用端口“40000”


有人知道我如何获取这些信息吗?

您可以运行下面的命令来获取可执行文件及其PID的信息

netstat -a -n -o -b | find "iisexpress.exe"

PID似乎是4(系统),因为实际侦听套接字位于名为的服务下

我查看了iisexpresstray.exe用来提供所有正在运行的IISExpress应用程序列表的内容。谢天谢地,它是易于反编译的托管.NET代码(全部在iisexpresstray.dll中)

它似乎至少有三种不同的方式来获取进程的端口号:

  • 从命令行参数读取
    /port
    (我们知道这是不可靠的)
  • 运行
    netsh http show servicestate view=requestq
    并解析输出
  • 调用Microsoft.Web.RuntimeStatusClient.GetWorkerProcess(pid)并解析站点URL
  • 不幸的是,iisexpresstray.dll中的大多数有用的东西,如
    IisExpressHelper
    类,都声明为
    internal
    (尽管我认为有工具可以生成包装器或复制程序集并公布所有内容)

    我选择使用Microsoft.Web.dll。它位于我的GAC中,但由于某些原因,它没有出现在Visual Studio中可添加为引用的程序集列表中,因此我只是从我的GAC中复制了该文件。拥有Microsoft.Web.dll后,只需使用以下代码:

        using (var runtimeStatusClient = new RuntimeStatusClient())
        {
          var workerProcess = runtimeStatusClient.GetWorkerProcess(process.Id);
          // Apparently an IISExpress process can run multiple sites/applications?
          var apps = workerProcess.RegisteredUrlsInfo.Select(r => r.Split('|')).Select(u => new { SiteName = u[0], PhysicalPath = u[1], Url = u[2] });
          // If we just assume one app
          return new Uri(apps.FirstOrDefault().Url).Port;
         }
    
    您还可以调用
    RuntimeClient.getAllWorkerProcess
    仅检索实际的工作进程

    我也查看了registeredurlinfo(在Microsoft.Web.dll中),发现它使用了两个COM接口

  • IRsca2_核心
    F90F62AB-EE00-4E4F-8EA6-3805B6B25CDD
  • IRsca2\u工作流程
    B1341209-7F09-4ECD-AE5F-3EE40D921870
  • 最后,我读到一个版本的Microsoft.Web.Administration显然能够读取IISExpress应用程序信息,但信息非常稀少,我在系统上找到的那个版本甚至不允许我在没有管理员权限的情况下实例化
    ServerManager
    我在@makhdumi的回答中:

    用法:

    static public bool TryGetCurrentProcessRegisteredHttpPort(out List<int> ports, out Exception ex)
    {
        NetshInvoker netsh = new NetshInvoker();
        return netsh.TryGetHttpPortUseByProcessId(Process.GetCurrentProcess().Id, out ports, out ex);
    }
    
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    
    namespace YourCompanyName.Server.ServerCommon.Utility
    {
        /// <summary>
        /// Invoke netsh.exe and extract information from its output.
        /// Source: @crokusek, https://stackoverflow.com/questions/32196188
        ///         @GETah, https://stackoverflow.com/a/8274758/538763
        /// </summary>
        public class NetshInvoker
        {
            const string NetshHttpShowServiceStateViewRequestqArgs = "http show servicestate view=requestq";
    
            public NetshInvoker()
            {
            }
    
            /// <summary>
            /// Call netsh.exe to determine the http port number used by a given windowsPid (e.g. an IIS Express process)
            /// </summary>
            /// <param name="windowsPid">For example an IIS Express process</param>
            /// <param name="port"></param>
            /// <param name="ex"></param>
            /// <returns></returns>
            public bool TryGetHttpPortUseByProcessId(Int32 windowsPid, out List<Int32> ports, out Exception ex)
            {
                ports = null;
    
                try
                {
                    if (!TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out ex))
                        return false;
    
                    if (!pidToUrlMap.TryGetValue(windowsPid, out List<string> urls))
                    {
                        throw new Exception(String.Format("Unable to locate windowsPid {0} in '{1}' output.",
                            windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
                    }
    
                    if (!urls.Any())
                    {
                        throw new Exception(String.Format("WindowsPid {0} did not reference any URLs in '{1}' output.",
                            windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
                    }
    
                    ports = urls
                        .Select(u => new Uri(u).Port)
                        .ToList();
    
                    return true;
                }
                catch (Exception ex_)
                {
                    ex = ex_;
                    return false;
                }
            }
    
            private bool TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out Exception ex)
            {
                if (!TryExecNetsh(NetshHttpShowServiceStateViewRequestqArgs, out string output, out ex))
                {
                    pidToUrlMap = null;
                    return false;
                }
    
                bool gotRequestQueueName = false;
                bool gotPidStart = false;
                int currentPid = 0;
                bool gotUrlStart = false;
    
                pidToUrlMap = new Dictionary<int, List<string>>();
    
                foreach (string line in output.Split('\n').Select(s => s.Trim()))
                {
                    if (!gotRequestQueueName)
                    {
                        gotRequestQueueName = line.StartsWith("Request queue name:");
                    }
                    else if (!gotPidStart)
                    {
                        gotPidStart = line.StartsWith("Process IDs:");
                    }
                    else if (currentPid == 0)
                    {
                        Int32.TryParse(line, out currentPid);   // just get the first Pid, ignore others.
                    }
                    else if (!gotUrlStart)
                    {
                        gotUrlStart = line.StartsWith("Registered URLs:");
                    }
                    else if (line.ToLowerInvariant().StartsWith("http"))
                    {
                        if (!pidToUrlMap.TryGetValue(currentPid, out List<string> urls))
                            pidToUrlMap[currentPid] = urls = new List<string>();
    
                        urls.Add(line);
                    }
                    else // reset
                    {
                        gotRequestQueueName = false;
                        gotPidStart = false;
                        currentPid = 0;
                        gotUrlStart = false;
                    }
                }
                return true;
            }
    
            private bool TryExecNetsh(string args, out string output, out Exception exception)
            {
                output = null;
                exception = null;
    
                try
                {
                    // From @GETah, https://stackoverflow.com/a/8274758/538763
    
                    Process p = new Process();
                    p.StartInfo.FileName = "netsh.exe";
                    p.StartInfo.Arguments = args;
                    p.StartInfo.UseShellExecute = false;
                    p.StartInfo.RedirectStandardOutput = true;
                    p.Start();
    
                    output = p.StandardOutput.ReadToEnd();
                    return true;
                }
                catch (Exception ex)
                {
                    exception = ex;
                    return false;
                }
            }
        }
    }
    
    静态公共bool TryGetCurrentProcessRegisteredHttpPort(输出列表端口,输出异常ex)
    {
    NetshInvoker netsh=新的NetshInvoker();
    返回netsh.TryGetHttpPortUseByProcessId(Process.GetCurrentProcess().Id,out端口,out ex);
    }
    
    实施:

    static public bool TryGetCurrentProcessRegisteredHttpPort(out List<int> ports, out Exception ex)
    {
        NetshInvoker netsh = new NetshInvoker();
        return netsh.TryGetHttpPortUseByProcessId(Process.GetCurrentProcess().Id, out ports, out ex);
    }
    
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    
    namespace YourCompanyName.Server.ServerCommon.Utility
    {
        /// <summary>
        /// Invoke netsh.exe and extract information from its output.
        /// Source: @crokusek, https://stackoverflow.com/questions/32196188
        ///         @GETah, https://stackoverflow.com/a/8274758/538763
        /// </summary>
        public class NetshInvoker
        {
            const string NetshHttpShowServiceStateViewRequestqArgs = "http show servicestate view=requestq";
    
            public NetshInvoker()
            {
            }
    
            /// <summary>
            /// Call netsh.exe to determine the http port number used by a given windowsPid (e.g. an IIS Express process)
            /// </summary>
            /// <param name="windowsPid">For example an IIS Express process</param>
            /// <param name="port"></param>
            /// <param name="ex"></param>
            /// <returns></returns>
            public bool TryGetHttpPortUseByProcessId(Int32 windowsPid, out List<Int32> ports, out Exception ex)
            {
                ports = null;
    
                try
                {
                    if (!TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out ex))
                        return false;
    
                    if (!pidToUrlMap.TryGetValue(windowsPid, out List<string> urls))
                    {
                        throw new Exception(String.Format("Unable to locate windowsPid {0} in '{1}' output.",
                            windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
                    }
    
                    if (!urls.Any())
                    {
                        throw new Exception(String.Format("WindowsPid {0} did not reference any URLs in '{1}' output.",
                            windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
                    }
    
                    ports = urls
                        .Select(u => new Uri(u).Port)
                        .ToList();
    
                    return true;
                }
                catch (Exception ex_)
                {
                    ex = ex_;
                    return false;
                }
            }
    
            private bool TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out Exception ex)
            {
                if (!TryExecNetsh(NetshHttpShowServiceStateViewRequestqArgs, out string output, out ex))
                {
                    pidToUrlMap = null;
                    return false;
                }
    
                bool gotRequestQueueName = false;
                bool gotPidStart = false;
                int currentPid = 0;
                bool gotUrlStart = false;
    
                pidToUrlMap = new Dictionary<int, List<string>>();
    
                foreach (string line in output.Split('\n').Select(s => s.Trim()))
                {
                    if (!gotRequestQueueName)
                    {
                        gotRequestQueueName = line.StartsWith("Request queue name:");
                    }
                    else if (!gotPidStart)
                    {
                        gotPidStart = line.StartsWith("Process IDs:");
                    }
                    else if (currentPid == 0)
                    {
                        Int32.TryParse(line, out currentPid);   // just get the first Pid, ignore others.
                    }
                    else if (!gotUrlStart)
                    {
                        gotUrlStart = line.StartsWith("Registered URLs:");
                    }
                    else if (line.ToLowerInvariant().StartsWith("http"))
                    {
                        if (!pidToUrlMap.TryGetValue(currentPid, out List<string> urls))
                            pidToUrlMap[currentPid] = urls = new List<string>();
    
                        urls.Add(line);
                    }
                    else // reset
                    {
                        gotRequestQueueName = false;
                        gotPidStart = false;
                        currentPid = 0;
                        gotUrlStart = false;
                    }
                }
                return true;
            }
    
            private bool TryExecNetsh(string args, out string output, out Exception exception)
            {
                output = null;
                exception = null;
    
                try
                {
                    // From @GETah, https://stackoverflow.com/a/8274758/538763
    
                    Process p = new Process();
                    p.StartInfo.FileName = "netsh.exe";
                    p.StartInfo.Arguments = args;
                    p.StartInfo.UseShellExecute = false;
                    p.StartInfo.RedirectStandardOutput = true;
                    p.Start();
    
                    output = p.StandardOutput.ReadToEnd();
                    return true;
                }
                catch (Exception ex)
                {
                    exception = ex;
                    return false;
                }
            }
        }
    }
    
    使用系统;
    使用System.Collections.Generic;
    使用系统诊断;
    使用System.Linq;
    命名空间YourCompanyName.Server.ServerCommon.Utility
    {
    /// 
    ///调用netsh.exe并从其输出中提取信息。
    ///资料来源:@crokusek,https://stackoverflow.com/questions/32196188
    ///@GETah,https://stackoverflow.com/a/8274758/538763
    /// 
    公共类NetshInvoker
    {
    常量字符串NetshHttpShowServiceStateViewRequestqArgs=“http show servicestate view=requestq”;
    公共NetshInvoker()
    {
    }
    /// 
    ///调用netsh.exe以确定给定windowsPid(例如IIS Express进程)使用的http端口号
    /// 
    ///例如,IIS Express进程
    /// 
    /// 
    /// 
    public bool TryGetHttpPortUseByProcessId(Int32 windowsPid,输出列表端口,输出异常ex)
    {
    端口=空;
    尝试
    {
    if(!TryQueryProcessIdRegisteredUrls(输出字典pidToUrlMap,输出ex))
    返回false;
    如果(!pidToUrlMap.TryGetValue(windowsPid,输出列表URL))
    {
    抛出新异常(String.Format(“无法在“{1}”输出中找到windowsPid{0}”,
    windowsPid,“netsh”+netshhtpShowServiceStateViewRequestQargs);
    }
    如果(!url.Any())
    {
    抛出新异常(String.Format(“WindowsPid{0}未引用“{1}”输出中的任何URL。”,
    windowsPid,“netsh”+netshhtpShowServiceStateViewRequestQargs);
    }
    端口=URL
    .Select(u=>newURI(u.Port)
    .ToList();
    返回true;
    }
    捕获(例外情况除外)
    {
    ex=ex;
    返回false;
    }
    }
    私有bool TryQueryProcessIdRegisteredUrls(out Dictionary pidToUrlMap,out Exception ex)
    {
    if(!TryExecNetsh(NetshHttpShowServiceStateViewRequestqArgs,out字符串输出,out ex))
    {
    pidToUrlMap=null;
    返回false;
    }
    bool gotRequestQueueName=false;
    bool-gotPidStart=false;
    int currentPid=0;
    bool gotUrlStart=false;
    pidToUrlMap=新字典();
    foreach(output.Split('\n')中的字符串行。选择(s=>s.Trim())
    {
    如果(!gotRequestQueueName)
    {
    gotRequestQueueName=line.StartsWith(“请求队列名称:”);
    }
    否则如果(!gotPidStart)
    {
    gotPidStart=line.StartsWith(“过程