最近一项目中要求显示网络流量,而且必须使用c#。
事实上,调用 iphlpapi.dll 的 getiftable api 可以轻易获得网络信息和网络流量。只是要在c#中实现还是比较复杂。
先看看怎么定义该 api
[dllimport("iphlpapi.dll")]
extern static public uint getiftable(byte[] piftable, ref uint pdwsize, bool border);
本来想把 piftable 定义为 intptr,但是这样的结果是,获取的信息是错误的(直到现在都不知是什么原因)。
但显然定义为 byte[] 是不能直接使用的。幸好在 google code search 找到了三个类:
customtmarshaler.cs
using system;
using system.io;
using system.collections;
using system.reflection;
using system.runtime.interopservices;
using system.threading;
namespace lemony.systeminfo
{
/**//// <summary>
/// custommarshaler class implementation.
/// </summary>
public abstract class custommarshaler
{
fields#region fields
// the internal buffer
internal byte[] data;
private memorystream stream;
private binaryreader binreader;
private binarywriter binwriter;
#endregion
constructors#region constructors
public custommarshaler()
{
}
#endregion
public methods#region public methods
public void deserialize()
{
if (data != null)
{
if (binreader != null)
{
binreader.close();
stream.close();
}
// create a steam from byte array
stream = new memorystream(data);
binreader = new binaryreader(stream, system.text.encoding.unicode);
readfromstream(binreader);
binreader.close();
}
}
public void serialize()
{
if (data != null)
{
stream = new memorystream(data);
binwriter = new binarywriter(stream, system.text.encoding.unicode);
writetostream(binwriter);
binwriter.close();
}
}
public int getsize()
{
int size = 0;
fieldinfo[] fields = this.gettype().getfields(bindingflags.public | bindingflags.instance);
foreach (fieldinfo field in fields )
{
if (field.fieldtype.isarray)
{
size += getfieldsize(field);
}
else if (field.fieldtype == typeof(string))
{
size += getfieldsize(field)*2;
}
else if (field.fieldtype.isprimitive)
{
size += marshal.sizeof(field.fieldtype);
}
}
return size;
}
#endregion
properties#region properties
public byte[] bytearray
{
get
{
return data;
}
}
#endregion
virtual and protected methods#region virtual and protected methods
public virtual void readfromstream(binaryreader reader)
{
object[] param = null;
// get all public fields
fieldinfo[] fields = this.gettype().getfields(bindingflags.public | bindingflags.instance);
// loop through the fields
foreach(fieldinfo field in fields)
{
// retrieve the read method from readmethods hashtable
methodinfo method = (methodinfo)marshallingmethods.readmethods[field.fieldtype];
if (field.fieldtype.isarray)
{
type element = field.fieldtype.getelementtype();
if (element.isvaluetype && element.isprimitive)
{
if ((element == typeof(char)) || element == typeof(byte))
{
param = new object[1];
param[0] = getfieldsize(field);
field.setvalue(this, method.invoke(reader, param));
}
else // any other value type array
{
param = new object[2];
param[0] = reader;
param[1] = getfieldsize(field);
field.setvalue(this, method.invoke(null, param));
}
}
else // array of sub structures
{
int size = getfieldsize(field);
method = (methodinfo)marshallingmethods.readmethods[typeof(custommarshaler)];
array objarray = array.createinstance(element, size);
for(int i=0;i<size;i++)
{
objarray.setvalue(activator.createinstance(element), i);
method.invoke(objarray.getvalue(i), new object[]{reader});
}
field.setvalue(this, objarray);
}
}
else if (field.fieldtype == typeof(string))
{
param = new object[2];
param[0] = reader;
param[1] = getfieldsize(field);
field.setvalue(this, method.invoke(null, param));
}
else if (field.fieldtype.isvaluetype && field.fieldtype.isprimitive)// regular value type
{
field.setvalue(this, method.invoke(reader, null));
}
else //process substructure
{
custommarshaler substruct = (custommarshaler)activator.createinstance(field.fieldtype);
substruct.readfromstream(reader);
}
}
}
public virtual void writetostream(binarywriter writer)
{
object[] param = null;
fieldinfo[] fields = this.gettype().getfields(bindingflags.public | bindingflags.instance);
foreach(fieldinfo field in fields)
{
// check if we have any value
object value = field.getvalue(this);
methodinfo method = (methodinfo)marshallingmethods.writemethods[field.fieldtype];
if (field.fieldtype.isarray)
{
type element = field.fieldtype.getelementtype();
if (element.isvaluetype && element.isprimitive)
{
//method.invoke(writer, new object[] {value});
array arrobject = (array)field.getvalue(this);
param = new object[2];
param[0] = writer;
param[1] = arrobject;
method.invoke(null, param);
}
else
{
//get field size
int size = getfieldsize(field);
//get writetostream method
method = (methodinfo)marshallingmethods.writemethods[typeof(custommarshaler)];
array arrobject = (array)field.getvalue(this);
for(int i=0;i<size;i++)
{
method.invoke(arrobject.getvalue(i), new object[]{writer});
}
}
}
else if (field.fieldtype == typeof(string))
{
param = new object[3];
param[0] = writer;
param[1] = field.getvalue(this);
param[2] = getfieldsize(field);
method.invoke(null, param);
}
else if (field.fieldtype.isvaluetype && field.fieldtype.isprimitive)// regular value type
{
method.invoke(writer, new object[] {value});
}
}
}
protected int getfieldsize(fieldinfo field)
{
int size = 0;
custommarshalasattribute attrib = (custommarshalasattribute)field.getcustomattributes(typeof(custommarshalasattribute), true)[0];
if (attrib != null)
{
if (attrib.sizefield != null)
{
fieldinfo sizefield = this.gettype().getfield(attrib.sizefield);
size = (int)sizefield.getvalue(this);
}
else
{
size = attrib.sizeconst;
}
}
return size;
}
#endregion
helper methods#region helper methods
private static bool comparebytearrays (byte[] data1, byte[] data2)
{
// if both are null, they're equal
if (data1==null && data2==null)
{
return true;
}
// if either but not both are null, they're not equal
if (data1==null || data2==null)
{
return false;
}
if (data1.length != data2.length)
{
return false;
}
for (int i=0; i < data1.length; i++)
{
if (data1[i] != data2[i])
{
return false;
}
}
return true;
}
#endregion
}
marshallingmethods class#region marshallingmethods class
/**//// <summary>
/// marshallingmethods class implementation.
/// </summary>
public class marshallingmethods
{
public static hashtable readmethods = new hashtable();
public static hashtable writemethods = new hashtable();
constructors#region constructors
static marshallingmethods()
{
// read methods
readmethods.add(typeof(bool), typeof(binaryreader).getmethod("readboolean"));
readmethods.add(typeof(byte), typeof(binaryreader).getmethod("readbyte"));
readmethods.add(typeof(system.sbyte), typeof(binaryreader).getmethod("readsbyte"));
readmethods.add(typeof(system.single), typeof(binaryreader).getmethod("readsingle"));
readmethods.add(typeof(byte[]), typeof(binaryreader).getmethod("readbytes"));
readmethods.add(typeof(char[]), typeof(binaryreader).getmethod("readchars"));
readmethods.add(typeof(system.int16), typeof(binaryreader).getmethod("readint16"));
readmethods.add(typeof(system.int32), typeof(binaryreader).getmethod("readint32"));
readmethods.add(typeof(system.uint16), typeof(binaryreader).getmethod("readuint16"));
readmethods.add(typeof(system.uint32), typeof(binaryreader).getmethod("readuint32"));
readmethods.add(typeof(system.string), typeof(marshallingmethods).getmethod("readstring"));
readmethods.add(typeof(system.datetime), typeof(marshallingmethods).getmethod("readdatetime"));
readmethods.add(typeof(system.int16[]), typeof(marshallingmethods).getmethod("readint16array"));
readmethods.add(typeof(system.int32[]), typeof(marshallingmethods).getmethod("readint32array"));
readmethods.add(typeof(system.uint16[]), typeof(marshallingmethods).getmethod("readuint16array"));
readmethods.add(typeof(system.uint32[]), typeof(marshallingmethods).getmethod("readuint32array"));
readmethods.add(typeof(custommarshaler), typeof(custommarshaler).getmethod("readfromstream"));
//write methods
writemethods.add(typeof(bool), typeof(binarywriter).getmethod("write", new type[]{typeof(bool)}));
writemethods.add(typeof(byte), typeof(binarywriter).getmethod("write", new type[]{typeof(byte)}));
writemethods.add(typeof(system.sbyte), typeof(binarywriter).getmethod("write", new type[]{typeof(system.sbyte)}));
writemethods.add(typeof(system.single), typeof(binarywriter).getmethod("write", new type[]{typeof(system.single)}));
//writemethods.add(typeof(byte[]), typeof(binarywriter).getmethod("write", new type[]{typeof(byte[])}));
//writemethods.add(typeof(char[]), typeof(binarywriter).getmethod("write", new type[]{typeof(char[])}));
writemethods.add(typeof(system.int16), typeof(binarywriter).getmethod("write", new type[]{typeof(system.int16)}));
writemethods.add(typeof(system.int32), typeof(binarywriter).getmethod("write", new type[]{typeof(system.int32)}));
writemethods.add(typeof(system.uint16), typeof(binarywriter).getmethod("write", new type[]{typeof(system.uint16)}));
writemethods.add(typeof(system.uint32), typeof(binarywriter).getmethod("write", new type[]{typeof(system.uint32)}));
writemethods.add(typeof(system.string), typeof(marshallingmethods).getmethod("writestring"));
writemethods.add(typeof(custommarshaler), typeof(custommarshaler).getmethod("writetostream"));
writemethods.add(typeof(bool[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(bool[]) }));
writemethods.add(typeof(char[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(char[]) }));
writemethods.add(typeof(short[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(short[]) }));
writemethods.add(typeof(ushort[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(ushort[]) }));
writemethods.add(typeof(int[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(int[]) }));
writemethods.add(typeof(uint[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(uint[]) }));
writemethods.add(typeof(long[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(long[]) }));
writemethods.add(typeof(ulong[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(ulong[]) }));
writemethods.add(typeof(float[]), typeof(marshallingmethods).getmethod("writearray", new type[] { typeof(binarywriter), typeof(float[]) }));
}
#endregion
static helper methods#region static helper methods
public static short[] readint16array(binaryreader reader, int count)
{
short[] result = new short[count];
for(int i=0;i<count;i++)
{
result[i] = reader.readint16();
}
return result;
}
public static int[] readint32array(binaryreader reader, int count)
{
int[] result = new int[count];
for(int i=0;i<count;i++)
{
result[i] = reader.readint32();
}
return result;
}
public static ushort[] readuint16array(binaryreader reader, int count)
{
ushort[] result = new ushort[count];
for(int i=0;i<count;i++)
{
result[i] = reader.readuint16();
}
return result;
}
public static uint[] readuint32array(binaryreader reader, int count)
{
uint[] result = new uint[count];
for(int i=0;i<count;i++)
{
result[i] = reader.readuint32();
}
return result;
}
public static string readstring(binaryreader reader, int count)
{
string result = "";
if (count == 0)
{
count = 255; //default
}
char[] data = reader.readchars(count);
result = new string(data).trimend('/0');
return result;
}
public static void writestring(binarywriter writer, string value, int size)
{
if (value!=null)
{
byte[] bstring = system.text.encoding.unicode.getbytes(value.substring(0, size));
writer.write(bstring);
}
}
public static datetime readdatetime(binaryreader reader)
{
return datetime.fromfiletime(reader.readint64());
}
public static void writearray(binarywriter writer, bool[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, char[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, byte[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, short[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, ushort[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, int[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, uint[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, long[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, ulong[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writearray(binarywriter writer, float[] arr)
{
for (int i = 0; i < arr.length; i++)
{
writer.write(arr[i]);
}
}
public static void writeserializers(binarywriter writer, custommarshaler[] arr)
{
for (int i = 0; i < arr.length; i++)
{
arr[i].writetostream(writer);
}
}
#endregion
}
#endregion
custommarshalasattribute#region custommarshalasattribute
/**//// <summary>
/// custommarshalasattribute implementaion.
/// </summary>
public sealed class custommarshalasattribute : attribute
{
public int sizeconst = 0;
public string sizefield = null;
}
#endregion
}
mib_ifrow.cs
using system;
using system.collections.generic;
using , system.text;
namespace lemony.systeminfo
{
public class mib_ifrow : custommarshaler
{
[custommarshalas(sizeconst = max_interface_name_len)]
public string wszname;
public uint dwindex; // index of the interface
public uint dwtype; // type of interface
public uint dwmtu; // max transmission unit
public uint dwspeed; // speed of the interface
public uint dwphysaddrlen; // length of physical address
[custommarshalas(sizeconst = maxlen_physaddr)]
public byte[] bphysaddr; // physical address of adapter
public uint dwadminstatus; // administrative status
public uint dwoperstatus; // operational status
public uint dwlastchange; // last time operational status changed
public uint dwinoctets; // octets received
public uint dwinucastpkts; // unicast packets received
public uint dwinnucastpkts; // non-unicast packets received
public uint dwindiscards; // received packets discarded
public uint dwinerrors; // erroneous packets received
public uint dwinunknownprotos; // unknown protocol packets received
public uint dwoutoctets; // octets sent
public uint dwoutucastpkts; // unicast packets sent
public uint dwoutnucastpkts; // non-unicast packets sent
public uint dwoutdiscards; // outgoing packets discarded
public uint dwouterrors; // erroneous packets sent
public uint dwoutqlen; // output queue length
public uint dwdescrlen; // length of bdescr member
[custommarshalas(sizeconst = maxlen_ifdescr)]
public byte[] bdescr; // interface description
private const int max_interface_name_len = 256;
private const int maxlen_physaddr = 8;
private const int maxlen_ifdescr = 256;
private const int max_adapter_name = 128;
}
}
mib_iftable.cs
using system;
using system.collections.generic;
using system.text;
namespace lemony.systeminfo
{
/**//// <summary>
/// iftable
/// </summary>
public class mib_iftable : custommarshaler
{
public int dwnumentries;
[custommarshalas(sizefield = "dwnumentries")]
public mib_ifrow[] table;
public mib_iftable()
{
this.data = new byte[this.getsize()];
}
public mib_iftable(int size)
{
this.data = new byte[size];
}
}
}
再定义一个 netinfo 类,存储网络信息
netinfo.cs
using system;
using system.collections.generic;
using system.text;
using system.runtime.interopservices;
namespace lemony.systeminfo
{
/**//// <summary>
/// 网络类型
/// </summary>
public enum nettype
{
other = 1,
ethernet = 6,
tokenring = 9,
fddi = 15,
ppp = 23,
loopback = 24,
slip = 28
};
/**//// <summary>
/// 网络状态
/// </summary>
public enum netstate
{
notoperational = 0,
operational = 1,
disconnected = 2,
connecting = 3,
connected = 4,
unreachable = 5
};
/**//// <summary>
/// 网络信息类
/// </summary>
public class netinfo
{
public netinfo()
{
}
private string m_name;
/**//// <summary>
/// 名称
/// </summary>
public string name
{
get { return m_name; }
set { m_name = value; }
}
private uint m_index;
/**//// <summary>
/// 有效编号
/// </summary>
public uint index
{
get { return m_index; }
set { m_index = value; }
}
private nettype m_type;
/**//// <summary>
/// 类型
/// </summary>
public nettype type
{
get { return m_type; }
set { m_type = value; }
}
private uint m_speed;
/**//// <summary>
/// 速度
/// </summary>
public uint speed
{
get { return m_speed; }
set { m_speed = value; }
}
private uint m_inoctets;
/**//// <summary>
/// 总接收字节数
/// </summary>
public uint inoctets
{
get { return m_inoctets; }
set { m_inoctets = value; }
}
private uint m_outoctets;
/**//// <summary>
/// 总发送字节数
/// </summary>
public uint outoctets
{
get { return m_outoctets; }
set { m_outoctets = value; }
}
private netstate m_status;
/**//// <summary>
/// 操作状态
/// </summary>
public netstate status
{
get { return m_status; }
set { m_status = value; }
}
private uint m_inerrors;
/**//// <summary>
/// 总错收字节数
/// </summary>
public uint inerrors
{
get { return m_inerrors; }
set { m_inerrors = value; }
}
private uint m_outerrors;
/**//// <summary>
/// 总错发字节数
/// </summary>
public uint outerrors
{
get { return m_outerrors; }
set { m_outerrors = value; }
}
private uint m_inunknownprotos;
/**//// <summary>
/// 未知协议共收字节数
/// </summary>
public uint inunknownprotos
{
get { return m_inunknownprotos; }
set { m_inunknownprotos = value; }
}
private string m_physaddr;
/**//// <summary>
/// 物理地址
/// </summary>
public string physaddr
{
get { return m_physaddr; }
set { m_physaddr = value; }
}
}
}
ok,现在可以获取网络信息了
/**//// <summary>
/// get iftable
/// </summary>
/// <returns>mib_iftable class</returns>
private static mib_iftable getalliftable()
{
//缓冲区大小
uint dwsize = 0;
//获取缓冲区大小
uint ret = getiftable(null, ref dwsize, false);
if (ret == 50)
{
//此函数仅支持于 win98/nt 系统
return null;
}
//定义,获取 mib_iftable 对象
mib_iftable tbl = new mib_iftable((int)dwsize);
ret = getiftable(tbl.bytearray, ref dwsize, false);
//如果不成功
if (ret != 0)
{
return null;
}
return tbl;
}
/**//// <summary>
/// get netinfo class
/// </summary>
/// <param name="row">mib_ifrow class</param>
/// <returns>netinfo class</returns>
private static netinfo getnetinfo(mib_ifrow row)
{
netinfo ninfo = new netinfo();
ninfo.index = row.dwindex;
ninfo.name = encoding.ascii.getstring(row.bdescr, 0, (int)row.dwdescrlen);
ninfo.physaddr = getphysaddr(row.bphysaddr, (int)row.dwphysaddrlen);
ninfo.type = (nettype)row.dwtype;
ninfo.status = (netstate)row.dwoperstatus;
ninfo.speed = row.dwspeed;
ninfo.inerrors = row.dwinerrors;
ninfo.inoctets = row.dwinoctets;
ninfo.inunknownprotos = row.dwinunknownprotos;
ninfo.outerrors = row.dwouterrors;
ninfo.outoctets = row.dwoutoctets;
return ninfo;
}
/**//// <summary>
/// 获取所有的网络信息
/// </summary>
/// <returns>netinfo 网络信息范型</returns>
public static list<netinfo> getallnetinfo()
{
//定义范型
list<netinfo> ninfos = new list<netinfo>();
//定义,获取 mib_iftable 对象
mib_iftable tbl = getalliftable();
//如果成功
if (tbl != null)
{
tbl.deserialize();
for (int i = 0; i < tbl.table.length; i++)
{
ninfos.add(getnetinfo(tbl.table[i]));
}
}
return ninfos;
}
ps:事实上,我把获取网络、cpu、内存、磁盘、进程信息等功能封装起来,并做了一个比较完善的 windows 任务管理器,整理完后发布源码。
新闻热点
疑难解答