using System;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpPcap;
using SharpPcap.WinPcap;
using PacketDotNet;
using Demo.STP.Sniff.Packets;

namespace Demo.STP.Sniff
{
    /// <summary>
    /// 嗅探器,提供原始数据源
    /// </summary>
    public sealed class Sniffer
    {
        #region Instance
        private static readonly Lazy<Sniffer> _lazy =
            new Lazy<Sniffer>(() => new Sniffer());

        public static Sniffer Instance
        {
            get { return _lazy.Value; }
        }

        private Sniffer() { }
        #endregion Instance

        #region Init
        /// <summary>
        /// 初始化嗅探器
        /// </summary>
        /// <param name="ipAddress">需拦截网卡所配IP</param>
        /// <param name="filter">数据包过滤规则</param>
        public void Init(string ipAddress, string filter = "")
        {
            var network = Demo.STP.Common.NetHelper.GetNetwork(ipAddress);
            if (network == null)
                throw new ArgumentException(string.Format("Invalid IPAddress {0}.", ipAddress));

            this._currentDevice = WinPcapDeviceList.Instance.Where(deviceItem =>
                string.Equals(network.Name, deviceItem.Interface.FriendlyName, StringComparison.OrdinalIgnoreCase))
                .FirstOrDefault();

            if (this._currentDevice == null)
                throw new ArgumentException("无法从WinPcap找到对应网卡.");

            this._currentDevice.OnPacketArrival += device_OnPacketArrival;
            this._currentDevice.Open(DeviceMode.Normal);
            this._currentDevice.Filter = filter;
        }

        private void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            this._packetQueue.Enqueue(e.Packet);
        }
        #endregion Init

        #region Start Hook
        /// <summary>
        /// 启动嗅探器
        /// </summary>
        public void StartHook()
        {
            if (this._currentDevice == null)
                throw new ArgumentException("请先初始化嗅探器.");

            KeepHook = true;
            this._currentDevice.StartCapture();

            RawCapture rawCapture = null;

            Task.Factory.StartNew(() =>
            {
                while (KeepHook)
                {
                    if (this._packetQueue.IsEmpty)
                    {
                        //理论上能轻松应对所有终端
                        //如果吞吐量达不到要求,请删除Sleep,但会占用一个核心的全部时间
                        Thread.Sleep();
                        continue;
                    }
                    if (this._packetQueue.TryDequeue(out rawCapture))
                    {
                        var basePacket = this.AnalysisPacket(rawCapture);
                        if (basePacket.HasValue)
                        {
                            OnPacketArrival(new PacketArrivedEventArgs { BasePacket = basePacket.Value });
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }
        #endregion Start Hook

        #region Stop Hook
        /// <summary>
        /// 停止嗅探器
        /// </summary>
        public void StopHook()
        {
            if (this._currentDevice == null) return;

            KeepHook = false;

            if (this._currentDevice.Started)
                this._currentDevice.StopCapture();

            this._currentDevice.OnPacketArrival -= device_OnPacketArrival;
            this._currentDevice.Close();
        }
        #endregion Stop Hook

        #region 解析数据包
        private Nullable<IPBasePacket> AnalysisPacket(RawCapture rawCapture)
        {
            try
            {
                var rawPacket = rawCapture.ParseRawPacket();
                var ipPacket = rawPacket.ExtractTragetPacket<IpPacket>();
                if (ipPacket == null)
                    return null;

                EnumIPProtocol targetProtocol;
                var parseFlag = Enum.TryParse(ipPacket.Protocol.ToString(), true, out targetProtocol);
                if (!parseFlag)
                    return null;

                IPBasePacket basePacket = new IPBasePacket();
                basePacket.Protocol = targetProtocol;
                basePacket.IPVersion = ipPacket.Version.ToString();
                basePacket.SourceIP = ipPacket.SourceAddress.ToString();
                basePacket.TargetIP = ipPacket.DestinationAddress.ToString();

                dynamic tcp_udp_Packet = rawPacket.ExtractTragetPacket<TcpPacket>();
                if (tcp_udp_Packet == null)
                    tcp_udp_Packet = rawPacket.ExtractTragetPacket<UdpPacket>();

                if (tcp_udp_Packet != null)
                {
                    if (tcp_udp_Packet.PayloadData == null)
                        return null; 

                    basePacket.SourcePort = tcp_udp_Packet.SourcePort;
                    basePacket.TargetPort = tcp_udp_Packet.DestinationPort;

                    //basePacket.PacketLength = (uint)tcp_udp_Packet.Bytes.Length;
                    //basePacket.HeaderLength = (uint)tcp_udp_Packet.Header.Length;
                    //basePacket.MessageLength = (uint)tcp_udp_Packet.PayloadData.Length;

                    //basePacket.PacketBuffer = tcp_udp_Packet.Bytes;
                    //basePacket.HeaderBuffer = tcp_udp_Packet.Header;
                    //basePacket.MessageBuffer = tcp_udp_Packet.PayloadData;

                    basePacket.MessageLength = (uint)tcp_udp_Packet.PayloadData.Length;
                    basePacket.MessageBuffer = tcp_udp_Packet.PayloadData;
                }

                return basePacket;
            }
            catch
            {
                return null;
            }
        }
        #endregion 解析数据包

        #region PacketArrival Event
        public event EventHandler<PacketArrivedEventArgs> PacketArrival;

        internal void OnPacketArrival(PacketArrivedEventArgs e)
        {
            if (PacketArrival != null)
            {
                PacketArrival(this, e);
            }
        }

        public bool IsMonitorEmpty
        {
            get { return PacketArrival == null; }
        }
        #endregion PacketArrival Event

        #region Fields & Propertys
        public bool KeepHook { get; private set; }
        private WinPcapDevice _currentDevice;
        private ConcurrentQueue<RawCapture> _packetQueue = new ConcurrentQueue<RawCapture>();
        #endregion Fields & Propertys
    }

    public class PacketArrivedEventArgs : EventArgs
    {
        public IPBasePacket BasePacket { get; set; }
    }
}

Sniffer的完整代码,基于winpcap抓包统计吞吐量的更多相关文章

  1. winpcap抓包原理

    winpcap抓包原理 WinPcap 是由伯克利分组捕获库派生而来的分组捕获库,它是在Windows 操作平台上来实现对底层包的截取过滤.WinPcap 是 BPF 模型和 Libpcap 函数库在 ...

  2. 基于wireshark抓包分析TCP的三次握手

    1. TCP的三次握手 在TCP/IP协议通讯过程中,采用三次握手建立连接,从而保证连接的安全可靠. 所有基于TCP的通信都需要以两台主机的握手开始.这个握手过程主要是希望能达到以下不同的目的.[1] ...

  3. Python + winpcap抓包和发包

    winpcapy Python的winpcapy库可以简单地实现收发Layer2层(数据链路层,以太网)数据. winpcapy主页:https://github.com/orweis/winpcap ...

  4. NetAnalyzer笔记 之 三. 用C++做一个抓包程序

    [创建时间:2015-08-27 22:15:17] NetAnalyzer下载地址 经过前两篇的瞎扯,你是不是已经厌倦了呢,那么这篇让我们来点有意思的吧,什么,用C#.不,这篇我们先来C++的 Wi ...

  5. https wireshark抓包——要解密出原始数据光有ssl 证书还不行,还要有浏览器内的pre-master-secret(内存里)

    基于wireshark抓包的分析 首先使用wireshark并且打开浏览器,打开百度(百度使用的是HTTPS加密),随意输入关键词浏览. 我这里将抓到的包进行过滤.过滤规则如下 ip.addr == ...

  6. 软件测试必须掌握的抓包工具Wireshark,你会了么?

    作为软件测试工程师,大家在工作中肯定经常会用到各种抓包工具来辅助测试,比如浏览器自带的抓包工具-F12,方便又快捷:比如时下特别流行的Fiddler工具,使用各种web和APP测试的各种场景的抓包分析 ...

  7. charles 抓包 (二)

    本文基于charles 抓包 https (1)中的配置完成. 1.移动设备上的网络请求 打开要调试的APP,请求就会先发送到Charles,然后验证是否允许访问. 当点击允许后,可以在Proxy - ...

  8. 【毕业设计】基于Android的家校互动平台开发(内含完整代码和所有文档)——爱吖校推(你关注的,我们才推)

    ☆ 写在前面 之前答应大家的毕业答辩之后把所有文档贡献出来,现在答辩已过,LZ信守承诺,把所有文档开源到了GitHub(这个地址包含所有的代码和文档以及PPT,外层为简单的代码).还望喜欢的朋友们,不 ...

  9. 基于Linux C的socket抓包程序和Package分析 (一)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/guankle/article/details/27538031  測试执行平台:CentOS 6 ...

随机推荐

  1. 可轮播滚动的Tab选项卡

    前段时间有试着搭建个后台主题ui框架,有用到可支持滚动的Tab选项卡,模仿着H+后台主题ui框架中的代码造轮子改造了下,可惜代码在公司,不能把代码外发出来(感觉这样被限制了很多,对于这样的公司没办法, ...

  2. View and Data API Tips: how to make viewer full screen

    By Daniel Du If you have not heard of View and Data API, here is the idea, the View & Data API e ...

  3. 自定义ViewGroup须知

    自定义ViewGroup须知: 1.必须复写onMeasure和onLayout方法,根据容器的特性进行布局设计 2.复写onMeasure方法必须处理父布局设置宽或高为wrap_content情况下 ...

  4. Android入门开发时注意的两个问题

    android开发中的问题: . 开发应用时要访问网络往往会忘记添加网络权限 <uses-permission android:name="android.permission.INT ...

  5. iOS 疑难杂症 — — UITableView 添加 tableFooterView 旋转屏幕后收不到点击事件!!!

    声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblogs.com 农民伯伯: http://over140.cnblogs.com 正文 新手的烦恼你不懂 - - ## ...

  6. GIT命令行的使用

    新手了解 有不对的地方指点下 首先, 了解下什么是GIT,GIT是一款开元的分布式版本控制工具, 在世界上的所有分布式版本控制工具中,GIT是最简单,最流行,同时也是最常用的 相比于其他版本的控制工具 ...

  7. Ruby的require相关知识

    1. 在调用require xxx之前,需要确定xxx这个gem已经安装过了(使用gem install xxx,安装位置可以使用gem env列出),或者xxx是Ruby内置的标准函数库(StdLi ...

  8. 将String转化成Stream,将Stream转换成String

    using System;using System.IO;using System.Text;namespace CSharpConvertString2Stream{     class Progr ...

  9. Sql--order by、desc降序、top

    ---------通过order by 语句进行排序: --1.降序order by 列名desc --2.升序order by 列名   或order by 列名asc --3.order by语句 ...

  10. 如何查看Windows服务器运行了多长时间

    前言:有时候管理.维护Windows服务器需要定期重启服务器(为什么需要重启,你懂的),但是这个"定期"有时候会受很多因素影响,例如某台服务器忘了重启:某台服务器那个时间段业务繁忙 ...