windows下使用C#获取特定进程网络流量
2017-01-26 10:15
766 查看
最近老板接了一个中船重工的项目,需要做一个有关海军软件系统的组件评估项目,项目中有一个子项目需要获取特定进程的各种系统参数,项目使用.NET平台。在获取特定进程各种系统参数时,其它诸如进程ID,进程名,进程私有工作集,进程工作集,进程IO吞吐量,进程CPU占用率等都可以直接使用.NET中的相关API直接获取,例如使用PerformanceCounter对象可以获取进程私有工作集、进程工作集、进程IO吞吐量等,但是对于特定进程的网络上行流量和下行流量却没有办法直接使用.NET中API获取,网上也找了很多资料,了解到只能通过对特定进程使用的端口号进行抓包来获取进程网络流量,具体实现时自己也想过使用C#调用winpcap库,但由于实现比较复杂,所以就放弃了使用该方法。后来在网上找到了一个国外使用C#实现的winpcap库SharpPcap库,于是使用SharpPcap库实现了获取特定进程网络流量功能。准备工作是需要将SharpPcap库下载到计算机,然后再项目中引用PacketDotNet.dll和SharpPcap.dll,然后添加引用:
具体实现比较复杂,以下介绍一下实现中的核心部分:
首先定义ProcessPerformanceInfo类,用来记录进程相关信息,ProcessPerformanceInfo定义如下
定义一个ProcessPerformanceInfo类型的属性ProcInfo:
第一步:获取指定进程使用的所有端口号
由于一个进程可能使用多个端口号,因此监视一个进程流量时必须监视该进程使用的所有端口号,具体可以通过cmd执行命令netstat -ano并对结果进行分析。代码如下:
所获取的端口号都存放在ports里。
第二步:获取本机IP地址和本机网络设备(即网卡)
第三步:开始抓包,至于sharppcap库的使用方法,在官方有很详细的介绍:http://www.codeproject.com/Articles/12458/SharpPcap-A-Packet-Capture-Framework-for-NET
实现代码如下:
CaptureFlowRecv和CaptureFlowSend函数定义如下:
第四步:设置每秒刷新上行下行流量
第五步:测试部分代码
以上仅仅是核心部分实现的代码简介,旨在为读者提供思路,具体实现还需要添加很多接口和类来实现。最后附上自己运行后的截图
using SharpPcap; using PacketDotNet;
具体实现比较复杂,以下介绍一下实现中的核心部分:
首先定义ProcessPerformanceInfo类,用来记录进程相关信息,ProcessPerformanceInfo定义如下
//记录特定进程性能信息的类 public class ProcessPerformanceInfo : IDisposable { public int ProcessID { get; set; }//进程ID public string ProcessName { get; set; }//进程名 public float PrivateWorkingSet { get; set; }//私有工作集(KB) public float WorkingSet { get; set; }//工作集(KB) public float CpuTime { get; set; }//CPU占用率(%) public float IOOtherBytes { get; set; }//每秒IO操作(不包含控制操作)读写数据的字节数(KB) public int IOOtherOperations { get; set; }//每秒IO操作数(不包括读写)(个数) public long NetSendBytes { get; set; }//网络发送数据字节数 public long NetRecvBytes { get; set; }//网络接收数据字节数 public long NetTotalBytes { get; set; }//网络数据总字节数 public List<ICaptureDevice> dev = new List<ICaptureDevice>(); /// <summary> /// 实现IDisposable的方法 /// </summary> public void Dispose() { foreach (ICaptureDevice d in dev) { d.StopCapture(); d.Close(); } } }
定义一个ProcessPerformanceInfo类型的属性ProcInfo:
public ProcessPerformanceInfo ProcInfo { get; set; }
第一步:获取指定进程使用的所有端口号
由于一个进程可能使用多个端口号,因此监视一个进程流量时必须监视该进程使用的所有端口号,具体可以通过cmd执行命令netstat -ano并对结果进行分析。代码如下:
//进程id int pid = ProcInfo.ProcessID; //存放进程使用的端口号链表 List<int> ports = new List<int>(); #region 获取指定进程对应端口号 Process pro = new Process(); pro.StartInfo.FileName = "cmd.exe"; pro.StartInfo.UseShellExecute = false; pro.StartInfo.RedirectStandardInput = true; pro.StartInfo.RedirectStandardOutput = true; pro.StartInfo.RedirectStandardError = true; pro.StartInfo.CreateNoWindow = true; pro.Start(); pro.StandardInput.WriteLine("netstat -ano"); pro.StandardInput.WriteLine("exit"); Regex reg = new Regex("\\s+", RegexOptions.Compiled); string line = null; ports.Clear(); while ((line = pro.StandardOutput.ReadLine()) != null) { line = line.Trim(); if (line.StartsWith("TCP", StringComparison.OrdinalIgnoreCase)) { line = reg.Replace(line, ","); string[] arr = line.Split(','); if (arr[4] == pid.ToString()) { string soc = arr[1]; int pos = soc.LastIndexOf(':'); int pot = int.Parse(soc.Substring(pos + 1)); ports.Add(pot); } } else if (line.StartsWith("UDP", StringComparison.OrdinalIgnoreCase)) { line = reg.Replace(line, ","); string[] arr = line.Split(','); if (arr[3] == pid.ToString()) { string soc = arr[1]; int pos = soc.LastIndexOf(':'); int pot = int.Parse(soc.Substring(pos + 1)); ports.Add(pot); } } } pro.Close(); #endregion
所获取的端口号都存放在ports里。
第二步:获取本机IP地址和本机网络设备(即网卡)
//获取本机IP地址 IPAddress[] addrList = Dns.GetHostByName(Dns.GetHostName()).AddressList; string IP = addrList[0].ToString(); //获取本机网络设备 var devices = CaptureDeviceList.Instance; int count = devices.Count; if (count < 1) { Console.WriteLine("No device found on this machine"); return; }
第三步:开始抓包,至于sharppcap库的使用方法,在官方有很详细的介绍:http://www.codeproject.com/Articles/12458/SharpPcap-A-Packet-Capture-Framework-for-NET
实现代码如下:
//开始抓包 for (int i = 0; i < count; ++i) { for (int j = 0; j < ports.Count; ++j) { CaptureFlowRecv(IP, ports[j], i); CaptureFlowSend(IP, ports[j], i); } }
CaptureFlowRecv和CaptureFlowSend函数定义如下:
public void CaptureFlowSend(string IP, int portID, int deviceID) { ICaptureDevice device = (ICaptureDevice)CaptureDeviceList.New()[deviceID]; device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrivalSend); int readTimeoutMilliseconds = 1000; device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds); string filter = "src host " + IP + " and src port " + portID; device.Filter = filter; device.StartCapture(); ProcInfo.dev.Add(device); } public void CaptureFlowRecv(string IP, int portID, int deviceID) { ICaptureDevice device = CaptureDeviceList.New()[deviceID]; device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrivalRecv); int readTimeoutMilliseconds = 1000; device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds); string filter = "dst host " + IP + " and dst port " + portID; device.Filter = filter; device.StartCapture(); ProcInfo.dev.Add(device); }
private void device_OnPacketArrivalSend(object sender, CaptureEventArgs e) { var len = e.Packet.Data.Length; ProcInfo.NetSendBytes += len; } private void device_OnPacketArrivalRecv(object sender, CaptureEventArgs e) { var len = e.Packet.Data.Length; ProcInfo.NetRecvBytes += len; }
第四步:设置每秒刷新上行下行流量
/// <summary> /// 实时刷新性能参数 /// </summary> public void RefershInfo() { ProcInfo.NetRecvBytes = 0; ProcInfo.NetSendBytes = 0; ProcInfo.NetTotalBytes = 0; Thread.Sleep(1000); ProcInfo.NetTotalBytes = ProcInfo.NetRecvBytes + ProcInfo.NetSendBytes; }
第五步:测试部分代码
while (true) { Console.WriteLine("proc NetTotalBytes : " + ProcInfo.NetTotalBytes); Console.WriteLine("proc NetSendBytes : " + ProcInfo.NetSendBytes); Console.WriteLine("proc NetRecvBytes : " + ProcInfo.NetRecvBytes); //每隔1s调用刷新函数对性能参数进行刷新 RefershInfo(); } //最后要记得调用Dispose方法停止抓包并关闭设备 Proc.Dispose();
以上仅仅是核心部分实现的代码简介,旨在为读者提供思路,具体实现还需要添加很多接口和类来实现。最后附上自己运行后的截图
![](http://images.cnitblog.com/blog/225727/201310/12115543-d0624a3322bc46d0b9ae1f556d484a56.jpg)
相关文章推荐
- Wireshark基本介绍和学习TCP三次握手
- HTTP原型
- 命名空间“System.Web”中不存在类型或命名空间名称“HttpUtility”。是否缺少程序集引用?
- 【OTT】【IPTV】三大通信运营商2016年IPTV、OTT招标一览
- php通过http_user_agent判断用户设备类型(脑残版)
- CentOS故障排除详解(3): 网络环境
- 利用String类制作简单的网络爬虫
- linux的网络配置和传输文件
- HTTP 返回状态代码
- https证书
- rtsp over http
- QTcpSocket 发送和接收数据的几种方法
- java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
- Linux(CentOS)安装完成后连接网络
- tomcat配置问题:访问http://localhost:8080/ 遇到 Access Error: 404
- nmap常用命令及参数说明
- 改变您的HTTP服务器的缺省banner
- vmware下 ubuntu 16.04.1 设置静态ip地址
- Linux-ubuntu 日记( 1 )- 传输文件+连接网络
- 线性规划与网络流24——运输问题