【问题标题】:Missing network sent/received缺少网络发送/接收
【发布时间】:2012-04-17 09:28:27
【问题描述】:

我在这里关注答案:

Calculating Bandwidth

并按照他说的执行了所有操作。我的显示器是这样初始化的:

netSentCounter.CategoryName = ".NET CLR Networking";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = true;

我可以正确地看到Misc.GetInstanceName() 返回“MyProcessName[id]”。但是我不断收到实例在指定类别中不存在的异常。

我的理解是,在您实际发送或接收之前,不会创建净发送/接收的类别。

我已经按照答案中的描述添加了 app.config,如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.net>
        <settings>
            <performanceCounters enabled="true" />
        </settings>
    </system.net>
</configuration>

为什么我仍然收到错误消息?

这是我的监控代码:

public static class Monitoring
{
    private static PerformanceCounter netSentCounter = new PerformanceCounter();

    //Static constructor
    static Monitoring()
    {
        netSentCounter.CategoryName = ".NET CLR Networking";
        netSentCounter.CounterName = "Bytes Sent";
        netSentCounter.InstanceName = Misc.GetInstanceName();
        netSentCounter.ReadOnly = true;
    }

    /// <summary>
    /// Returns the amount of data sent from the current application in MB
    /// </summary>
    /// <returns></returns>
    public static float getNetSent()
    {
        return (float)netSentCounter.NextValue() / 1048576; //Convert to from Bytes to MB
    }
}

还有我的杂项课:

public static class Misc
{

    //Returns an instance name
   internal static string GetInstanceName()
    {
        // Used Reflector to find the correct formatting:
        string assemblyName = GetAssemblyName();
        if ((assemblyName == null) || (assemblyName.Length == 0))
        {
            assemblyName = AppDomain.CurrentDomain.FriendlyName;
        }
        StringBuilder builder = new StringBuilder(assemblyName);
        for (int i = 0; i < builder.Length; i++)
        {
            switch (builder[i])
            {
                case '/':
                case '\\':
                case '#':
                    builder[i] = '_';
                    break;
                case '(':
                    builder[i] = '[';
                    break;

                case ')':
                    builder[i] = ']';
                    break;
            }
        }
        return string.Format(CultureInfo.CurrentCulture,
                             "{0}[{1}]",
                             builder.ToString(),
                             Process.GetCurrentProcess().Id);
    }

    /// <summary>
    /// Returns an assembly name
    /// </summary>
    /// <returns></returns>
    internal static string GetAssemblyName()
    {
        string str = null;
        Assembly entryAssembly = Assembly.GetEntryAssembly();
        if (entryAssembly != null)
        {
            AssemblyName name = entryAssembly.GetName();
            if (name != null)
            {
                str = name.Name;
            }
        }
        return str;
    }
 }

编辑:我已经从 Windows 中打开了资源监视器以查看问题所在。尽管已将 app.config 设置为启动,但计数器并未启动。

这是我看到的(在我的应用程序发送网络活动之前和之后)

而且名称不是我的方法返回的名称。我的方法返回“SuperScraper[appId]”,而在资源中它被称为“Superscraper.vshost.exe”。

所以我现在有两个问题:

-我的计数器没有在应用启动时启动 - 名字不同

【问题讨论】:

  • 你能显示堆栈跟踪吗?什么是杂项? Here 都是代码,复制粘贴即可。
  • Misc 只是我使用的一个库。我将发布堆栈跟踪。
  • 调用堆栈几乎是空的。它所做的只是从我的库中调用该方法。问题是因为代码在库中而不是在我的主应用程序中吗?我的代码和你的很像。
  • 我刚刚重新链接了来自this answer 的代码。那个 Misc 库是你写的吗?你如何引用它?
  • 我编辑了代码以显示类名,因为它有点令人困惑。从代码中我调用getNetSent()。静态构造函数在第一次运行时调用Misc 以获取程序集名称。

标签: c# winforms networking performancecounter


【解决方案1】:

好吧,我终于想通了。 Calculating Bandwidth 列出的步骤似乎已过时,对 .Net 4 不再有效。

我将解释整个过程,以便您也可以这样做。

首先,您需要将其添加到您的 app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.net>
        <settings>
            <performanceCounters enabled="true" />
        </settings>
    </system.net>
</configuration>

在 .Net 4.0 之前,这使应用程序在启动时创建计数器(而不是例如,在应用程序发送请求时创建网络计数器)。在 .Net 4.0 中,这告诉它在使用计数器时创建计数器。 IE。如果您不设置此项,则永远不会创建计数器。

现在这是我浪费最多时间的地方。我的假设是错误的,即如果您创建一个与自然创建时具有相同名称的性能计数器,您将获得这些值。然而,这一切只是阻止了真正的计数器出现。

这样做:

//In .Net 4.0 the category is called .NET CLR Networking 4.0.0.0 and not .NET CLR Networking
netSentCounter.CategoryName = ".NET CLR Networking 4.0.0.0";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = false; //<==
netSentCounter.RawValue = 0;     //<==

简单地阻止真正的计数器。

您需要做的是以自然的方式启动它。最好的方法是在应用程序启动时简单地发送一个欺骗请求,然后使用以下命令“监听”性能计数器:

//Send spoof request here
netSentCounter.CategoryName = ".NET CLR Networking 4.0.0.0";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = true;

最后一点。实例名称不再是 ApplicationName[appId]。现在是:

[ApplicationName].exe_p[appId]_r[the CLR id hosting your application]_ad[ApplicationDomain]

希望这可以节省一些时间!!

【讨论】:

【解决方案2】:

好的,我尝试了您的示例。我也遇到过性能监视器中没有显示计数器,但是在我更改 ReadOnly 并设置 RawValue 属性后它确实出现了:

netSentCounter.CategoryName = ".NET CLR Networking";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = false; //<==
netSentCounter.RawValue = 0;     //<==

就我而言,我发现性能监视器中的实例名称采用以下格式:myapplicationname_pPID

所以在我更改了您的 GetInstanceName 方法行之后

return string.Format(CultureInfo.CurrentCulture,
                         "{0}[{1}]",
                         builder.ToString(),
                         Process.GetCurrentProcess().Id);

return string.Format(CultureInfo.CurrentCulture,
                     "{0}_p{1}",                
                     builder.ToString().ToLower(), //<== dont miss ToLower()
                     Process.GetCurrentProcess().Id);

计数器似乎开始工作了。

这里是add and remove counter instance的参考方法

还可以考虑在使用完后删除(netSentCounter.RemoveInstance()) 计数器。

【讨论】:

  • 我真的不知道它有什么问题。我已经设法使用您的代码创建它,但它从不返回任何内容。它所做的只是给我返回 0。如果我自己不创建它,它确实会返回值。你以为是因为netSentCounter.RawValue = 0;?你的返回值了吗?
  • 好吧,我没有测试过,我只是想弄清楚你为什么会出错。
  • 名称匹配,我在同一个地方创建它,但值永远不会改变。如果我不创建它并让它自己创建(例如通过发送请求),它会报告值。你能测试一下你是否有同样的行为吗?
猜你喜欢
  • 1970-01-01
  • 2016-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多