最近老板接了一个中船重工的项目,需要做一个有关海军软件系统的组件评估项目,项目中有一个子项目需要获取特定进程的各种系统参数,项目使用.NET平台。在获取特定进程各种系统参数时,其它诸如进程ID,进程名,进程私有工作集,进程工作集,进程IO吞吐量,进程CPU占用率等都可以直接使用.NET中的相关API直接获取,例如使用PerformanceCounter对象可以获取进程私有工作集、进程工作集、进程IO吞吐量等,但是对于特定进程的网络上行流量和下行流量却没有办法直接使用.NET中API获取,网上也找了很多资料,了解到只能通过对特定进程使用的端口号进行抓包来获取进程网络流量,具体实现时自己也想过使用C#调用winpcap库,但由于实现比较复杂,所以就放弃了使用该方法。后来在网上找到了一个国外使用C#实现的winpcap库SharpPcap库,于是使用SharpPcap库实现了获取特定进程网络流量功能。准备工作是需要将SharpPcap库下载到计算机,然后再项目中引用PacketDotNet.dll和SharpPcap.dll,然后添加引用:

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(',');
                    ] == pid.ToString())
                    {
                        ];
                        int pos = soc.LastIndexOf(':');
                        ));
                        ports.Add(pot);
                    }
                }
                else if (line.StartsWith("UDP", StringComparison.OrdinalIgnoreCase))
                {
                    line = reg.Replace(line, ",");
                    string[] arr = line.Split(',');
                    ] == pid.ToString())
                    {
                        ];
                        int pos = soc.LastIndexOf(':');
                        ));
                        ports.Add(pot);
                    }
                }
            }
            pro.Close();
            #endregion

所获取的端口号都存放在ports里。

第二步:获取本机IP地址和本机网络设备(即网卡)

//获取本机IP地址
            IPAddress[] addrList = Dns.GetHostByName(Dns.GetHostName()).AddressList;
            ].ToString();
            //获取本机网络设备
            var devices = CaptureDeviceList.Instance;
            int count = devices.Count;
            )
            {
                Console.WriteLine("No device found on this machine");
                return;
            }

第三步:开始抓包,至于sharppcap库的使用方法,在官方有很详细的介绍:http://www.codeproject.com/Articles/12458/SharpPcap-A-Packet-Capture-Framework-for-NET

实现代码如下:

//开始抓包
            ; i < count; ++i)
            {
                ; 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);

            ;
            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);

            ;
            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 = ;
            ProcInfo.NetSendBytes = ;
            ProcInfo.NetTotalBytes = ;
            Thread.Sleep();
            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();

以上仅仅是核心部分实现的代码简介,旨在为读者提供思路,具体实现还需要添加很多接口和类来实现。最后附上自己运行后的截图

windows下使用C#获取特定进程网络流量的更多相关文章

  1. Linux下实现脚本监测特定进程占用内存情况

    Linux系统下,我们可以利用以下命令来获取特定进程的运行情况: cat /proc/$PID/status 其中PID是具体的进程号,这个命令打印出/proc/特定进程/status文件的内容,信息 ...

  2. C++ 获取特定进程的CPU使用率<转>

    C++ 获取特定进程的CPU使用率 近来发现笔记本在关闭屏幕后风扇转得特别快,打开屏幕后看任务管理器,风扇马上减速,也没有发现大量占用CPU的进程.于是想写一个小程序在后台记录每个进程的CPU使用情况 ...

  3. C#获取特定进程CPU和内存使用率

    首先是获取特定进程对象,可以使用Process.GetProcesses()方法来获取系统中运行的所有进程,或者使用Process.GetCurrentProcess()方法来获取当前程序所对应的进程 ...

  4. Windows下如何创建低权限进程

       1.  前言 在使用 Sysinternals 出品的 Process Explorer 过程中,对 “Run as Limited User” 功能的实现方式颇感兴趣,一番搜寻之下发现Mark ...

  5. windows下bat批处理实现守护进程

    本文转自网络,由于找不到原作者,因而无法知道出处.如果有幸让原作者看到,请联系我加上.先转载至此. 最近几天加班加疯掉了,天天晚上没法睡.开发部的一个核心程序总是会自己宕机,然后需要手工去起,而这个服 ...

  6. windows下根据端口号杀死进程

    Windows不像Linux,Unix那样,ps -ef 查出端口和进程号,然后根据进程号直接kill进程. Windows根据端口号杀死进程要分三步: 第一步 根据端口号寻找进程号 C:\>n ...

  7. windows下捕获dump之守护进程

    一两个月前为产品写了一个独立的exe,由于产品使用的捕获dump是一个现成的进程外exe,如果以资源的方式集成它容易出现安全警告,由于时间关系没有寻求新的解决方法,还是遵循旧方案,不捕获dump. 最 ...

  8. windows下bat批处理实现守护进程(有日志)

    开发部的一个核心程序总是会自己宕机,然后需要手工去起,而这个服务的安全级别又很高,只有我可以操作,搞得我晚上老没法睡,昨晚实在受不了了,想起以前在hp-ux下写的shell守护进程,这回搞个windo ...

  9. CentOS7 监控进程网络流量工具安装

    服务器在做测试的时候,需要监控网络流量,用来了解在不同人数的时候服务器的网络使用量. 我们使用服务器环境是centos7,centos下通常使用iftop,或者nethogs来进行网络流量监控.这2个 ...

随机推荐

  1. Eclipse开发环境设置(Maven+Spring MVC+Flex)

    1. 环境设置 1.1. Java环境设置 1)JAVA_HOME D:\GreenSoftware\Java\Java8X64\jdk1.8.0_91 2)PATH ;%JAVA_HOME%/bin ...

  2. IOS开发札记(2015-08-20)

    View显示数据借助Model的一个比较好的理由也是因为:有时候从服务器获取的数据相同的value可能对应不同的key(服务端多人协作开发时经常会出现这种情况) 这里盗图描述一下使用Model的好处 ...

  3. html5快速入门(二)—— CSS简介

    前言: 1.HTML5的发展非常迅速,可以说已经是前端开发人员的标配,在电商类型的APP中更是运用广泛,这个系列的文章是本人自己整理,尽量将开发中不常用到的剔除,将经常使用的拿出来,使需要的朋友能够真 ...

  4. UITableview中怎么找到每个cell

    一个朋友问我:我在每个cell中都添加了两个按钮(记为btnA和btnB),点击btnA时,对应的cell中添加一个子控件,再点击btnB时,对应的cell中的子控件就移除,怎么做到? 百度了一下,发 ...

  5. 了解HTML CSS布局(层叠样式表)

    CSS全称为"层叠样式表(Cascading Style Sheets)", 它主要是用于定义HTML内容在浏览器内显示的样式, 比如文字, 颜色, 视觉上的静态效果, 布局等等. ...

  6. Javascript如何实现AOP

    简介: AOP(面向切面的编程)是为了解决功能的独立性与可维护性而提供的一种编程思想.当多个函数大量重复使用同一个功能时通过分层切分,将功能平衡的划分,从而提高低耦合性. JS中实现: index.h ...

  7. 具备 jQuery 经验的人如何学习AngularJS(附:学习路径)

    这是一个来自stackoverflow的问答,三哥直接把最佳回答搬过来了. 都说AngularJS的学习曲线异常诡异~~~ Q: “Thinking in AngularJS” if I have a ...

  8. [Erlang 0103] Erlang Resources 资讯小站

       好久没有写博客,是懒了吗?不是;前面两个月在紧张地推进一个项目,中间积累了一些RabbitMQ和Erlang的东西;本打算在项目结束之后赶紧总结一下,结果老婆怀孕之后生活节奏大乱:早起做饭,晚上 ...

  9. 浅析SQL SERVER执行计划中的各类怪相

    在查看执行计划或调优过程中,执行计划里面有些现象总会让人有些疑惑不解: 1:为什么同一条SQL语句有时候会走索引查找,有时候SQL脚本又不走索引查找,反而走全表扫描? 2:同一条SQL语句,查询条件的 ...

  10. LINUX下的PHP

    由于linux系统的稳定性,大部分的PHP服务器都被部署在linux上,而且像redis等扩展在linux能得到更好的支持,所以对于PHP程序员来说,使用linux的功底也相当重要,接下来总结一下我从 ...