发送/接收的网络丢失

时间:2012-04-17 09:28:28

标签: c# winforms networking performancecounter

我在这里听到答案:

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,但计数器仍未启动。

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

enter image description here

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

所以我现在有两个问题:

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

2 个答案:

答案 0 :(得分:4)

好的,我终于明白了。列出的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] _ {广告{1}}

希望这能节省一些时间!!

答案 1 :(得分:1)

好的,我试过你的例子。我还看到了在性能监视器中没有显示的计数器,但在我更改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())计数器。