잊지 않겠습니다.

전에 한번 정리한 소스를 한번 정리해보는 내용으로...

Marin과 Medic, FIrebet.. 이 3개의 unit가 존재를 하고, 이 unit은 Attack과 Move라는 기본 동작을 갖는다.
Move라는 동작은 모든 Unit이 동일한 동작을 할 수 있지만, Attack 방법은 각기 다르고, 기본적으로 Attack이라는 Method를
갖지만 내부 구현이 다른 동작이 되게 된다. 

따라서, 각기 다른 동작을 구현하는 Class를 따로 뽑아내서 구현하는 Strategy Pattern이 사용 가능하다. 

먼저, 각기 다른 Attack에 대한 동작을 구현하는 Rifle, Firebazuka, Heal Class를 구현한다.

class Rifle : IAttack
{
    #region IAttack Members

    public string Attack()
    {
        return "dddd...";
    }

    #endregion
}

public class Firebazuka : IAttack
{
    #region IAttack Members

    public string Attack()
    {
        return "Fire!!...............";
    }

    #endregion
}

public class Heal : IAttack
{
    #region IAttack Members

    public string Attack()
    {
        return "Heal... ";
    }

    #endregion
}
그리고, 이 Attack Method의 IAttack을 인자로 갖는 BaseUnit class를 만들어준다. 
BaseUnit은 각 Unit의 parent class가 된다. 

class Runner : IMove
{
    #region IMove Members

    public string MoveTo(string direction)
    {
        return String.Format("To :{0}, Move it!", direction);
    }

    #endregion
}

public abstract class BaseUnit
{
    protected IAttack attackMethod;
    protected IMove moveMethod;

    protected BaseUnit()
    {
        
    }

    protected BaseUnit(IAttack attackMethod, IMove moveMethod)
    {
        this.attackMethod = attackMethod;
        this.moveMethod = moveMethod;
    }

    public virtual String Attack()
    {
        return attackMethod.Attack();
    }

    public virtual String MoveTo(String direction)
    {
        return moveMethod.MoveTo(direction);
    }
}
이렇게 구성된 BaseUnit을 이용해서 Marin, Firebet, Medic을 구현해준다. 구현된 코드는 다음과 같다.


public class Marin : BaseUnit
{
    public Marin() : base(new Rifle(), new Runner())
    {
        
    }
}
public class Firebet : BaseUnit
{
    public Firebet() : base(new Firebazuka(), new Runner())
    {
        
    }
}
public class Medic : BaseUnit
{
    public Medic() : base(new Heal(), new Runner())
    {
        
    }
}
구현된 Class를 이용해서 Test Code를 작성하면 다음과 같다. 

//Marin, Medic, Firebet의 class 생성
BaseUnit unit1 = new Marin();
BaseUnit unit2 = new Marin();
BaseUnit unit3 = new Medic();
BaseUnit unit4 = new Firebet();

//BaseUnit으로 Attack, MoveTo를 모두 구현
Console.WriteLine(unit1.Attack());
Console.WriteLine(unit2.Attack());
Console.WriteLine(unit3.Attack());
Console.WriteLine(unit4.Attack());

Console.WriteLine(unit1.MoveTo("Direction"));
Console.WriteLine(unit2.MoveTo("Direction"));
Console.WriteLine(unit3.MoveTo("Direction"));
Console.WriteLine(unit4.MoveTo("Direction"));
Strategy Pattern은 같은 Interface에서 각각 다른 동작을 하는 class들을 구현하는 방법으로, 
Method의 주체가 되는 Rifle, Firebazuk, Heal class의 구성이 관건이다. 다른 것을 객체화하라. 라는 
Design pattern의 성경같은 구절이 생각난다. 
Posted by Y2K
,
네트워크 상태를 보다보면 port의 사용 정보를 알고 싶을 때가 많은데...
사용되는 Port의 정보를 알려주는 site. 

정말 별애별 사이트가 다 있다는 증거.;

http://www.seifried.org/security/ports/index.php


Posted by Y2K
,
Hyper-V 에서 Network Usage와 Process Usage를 얻어내기 위해서 WMI 뒤지기 삽질. -_-

이번에 WMI를 보면서 많은 생각이 든 것이, MS가 참 대단하다는 생각이 든다. 정말 여러 데이터들을 잘 모아뒀다는 그런 느낌이라고 해야지 될까. 
먼저 Performance Counter에 사용되는 WMI 들은 Win32_PerfFormattedData_, Win32_PerfRawData_ 두가지로 나뉘어진다. 이 두개의 데이터의 차이는 좀 더 알아보기 쉽게 변형된 데이터와 Raw Data의 차이를 가지고 있다. 예를 들어 Network Usage의 경우 FormattedData의 경우에는 Bytes/sec의 정보가 나온다. 그렇지만 Raw Data는 Bytes의 누적값으로 표현이 된다. 이렇게 약간약간 다른 값들이 있기 때문에, 좀 더 세밀하게 볼 필요성이 있다. 

뭐.. 바로 본론으로 들어가면, 필요한 WMI 정보와 WMI를 얻어내는데 필요한 Helper Class를 먼저 제작해줬다. 


public class WmiHelper
{
    private readonly ConnectionOptions _connectionOptions;
    public WmiHelper()
    {
        _connectionOptions = new ConnectionOptions()
                                {
                                    Impersonation = ImpersonationLevel.Impersonate,
                                    Username = Configure.UserName,
                                    Password = Configure.Password,
                                    Authentication = AuthenticationLevel.Default,
                                    EnablePrivileges = true

                                };
    }

    protected ManagementObject GetManagementSingleObject(string wmiQuery, string wmiNamespace)
    {
        ManagementScope scope = new ManagementScope(wmiNamespace, _connectionOptions);
        try
        {
            scope.Connect();
            ObjectQuery query = new ObjectQuery(wmiQuery);
            using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
            {
                ManagementObjectCollection queryCollection = searcher.Get();
                return GetFirsManagementObject(queryCollection);
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }

    protected ManagementObjectCollection GetManagementCollection(string wmiQuery, string wmiNamespace)
    {
        ManagementScope scope = new ManagementScope(wmiNamespace, _connectionOptions);
        try
        {
            scope.Connect();
            ObjectQuery query = new ObjectQuery(wmiQuery);
            using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
            {
                ManagementObjectCollection queryCollection = searcher.Get();
                return queryCollection;
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }

    protected ManagementObject GetFirsManagementObject(ManagementObjectCollection managementObjectCollection)
    {
        if(managementObjectCollection.Count == 0)
        {
            return null;
        }
        else
        {
            var enumerator = managementObjectCollection.GetEnumerator();
            enumerator.MoveNext();
            return (ManagementObject)enumerator.Current;
        }
    }
}
WmiHelper는 Connection과 WMI Query를 Execute, 얻어진 ManagementObject와 ObjectCollection 얻어오는 일을 담당한다.
이제 Hyper-V의 Network Usage와 CPU Usage를 얻어오는 PerformanceCounter Class의 내용은 다음과 같다. 

public class VirtualMachinePerformanceCounter : WmiHelper
{
    //public long NetworkReadBytes { get; private set; }
    //public long NetworkWriteBytes { get; private set; }
    //public double CpuUsage { get; private set; }

    private readonly string _vmName;
    private readonly string _hostName;

    public VirtualMachinePerformanceCounter(string vmName, string hostName)
    {
        _vmName = vmName;
        _hostName = hostName;
    }

    public NetworkBandwidth MonitorNetworkBandwidth()
    {
        string wmiNamespace = string.Format("\\\\{0}\\Root\\cimv2", _hostName);
        string vmComputerName = GetVirtualComputerSystemGuidName();
        string wmiQuery =
            string.Format(
                "SELECT * FROM Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter WHERE Name like \"%_{0}--%\"",
                vmComputerName);
 
        ManagementObject managementObject = GetManagementSingleObject(wmiQuery, wmiNamespace);
        if(managementObject != null)
        {
            string recevedBytesString = managementObject["BytesReceivedPersec"].ToString();
            string sentBytesString = managementObject["BytesSentPersec"].ToString();
            string totalBytesString = managementObject["BytesPersec"].ToString();

            NetworkBandwidth networkBandwidth = new NetworkBandwidth(long.Parse(totalBytesString),
                                                         long.Parse(recevedBytesString), long.Parse(sentBytesString));
            Console.WriteLine("{0}\t{1}\t{2}", totalBytesString, recevedBytesString, sentBytesString);
            return networkBandwidth;
        }
        else
        {
            return NetworkBandwidth.Empty;
        }
    }


    public CpuUsage MonitorCpuUsage()
    {
        /*
        Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor
        Frequency_PerfTime
        PercentGuestRunTime
        Timestamp_PerfTime
        */
        string wmiNamespace = string.Format("\\\\{0}\\Root\\cimv2", _hostName);
        string wmiQuery = string.Format("SELECT Frequency_PerfTime,PercentGuestRunTime, Timestamp_PerfTime " +
                                        "FROM Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor " +
                                        "WHERE Name like \"{0}:%\"", _vmName);

        ManagementObjectCollection preManagementObjects = GetManagementCollection(wmiQuery, wmiNamespace);
        
        int logicalProcessCount = preManagementObjects.Count;

        if(logicalProcessCount == 0)
        {
            return CpuUsage.Empty;
        }
        else
        {
            ManagementObject m1 = GetFirsManagementObject(preManagementObjects);
            long frequencyPerfTime = long.Parse(m1["Frequency_PerfTime"].ToString());

            long percentGuestRunTime1 = long.Parse(m1["PercentGuestRunTime"].ToString());
            long timestampPerfTime1 = long.Parse(m1["Timestamp_PerfTime"].ToString());

            System.Threading.Thread.Sleep(1000);

            ManagementObject m2 = GetManagementSingleObject(wmiQuery, wmiNamespace);
            long percentGuestRunTime2 = long.Parse(m2["PercentGuestRunTime"].ToString());
            long timestampPerfTime2 = long.Parse(m2["Timestamp_PerfTime"].ToString());

            CpuUsage usage = new CpuUsage()
                                 {
                                     LogicalProcessCount = logicalProcessCount,
                                     FrequencyPerfTime = frequencyPerfTime,
                                     GuestRunTime1 = percentGuestRunTime1,
                                     GuestRunTime2 = percentGuestRunTime2,
                                     TimeStampPerTime1 = timestampPerfTime1,
                                     TimeStampPerTime2 = timestampPerfTime2
                                 };

            return usage;
        }
    }

    private string GetVirtualComputerSystemGuidName()
    {
        string wmiNamespace = string.Format("\\\\{0}\\Root\\virtualization", _hostName);
        string wmiQuery = string.Format("SELECT * FROM Msvm_ComputerSystem WHERE elementname = \"{0}\"", _vmName);

        ManagementObject managementObject = GetManagementSingleObject(wmiQuery, wmiNamespace);
        return (string)managementObject["Name"];
    }
}
간단히 코드 설명을 한다면, 

Network Usage는 Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter에서 얻어지는 값을 이용하면 된다. 
VM과 연관을 찾기 위해서는 root\virtualization에서 VirtualComputerSystem의 Name 값을 이용해서 like 검색을 하면 된다.

CPU Usage의 경우에는 http://blogs.msdn.com/tvoellm/archive/2008/07/14/how-to-get-processor-utilization-for-hyper-v-via-wmi.aspx를
참고.

* WmiHelper를 상속받는 것이 아닌, 아무래도 생성해서 Instance를 private로 들고 있는 것이 더 나았을 것 같다. 아무리 봐도.;
Posted by Y2K
,