SharpPcap 3.4使用范例

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpPcap;


namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            //显示SharpPcap版本
            string ver = SharpPcap.Version.VersionString;
            Console.WriteLine("SharpPcap {0}", ver);

            //获取网络设备
            var devices = LivePcapDeviceList.Instance;
            if (devices.Count < 1)
            {
                Console.WriteLine("找不到网络设备");
                return;
            }

            Console.WriteLine();
            Console.WriteLine("以下是目前本计算机上的活动网络设备:");
            Console.WriteLine("----------------------------------------------------");
            Console.WriteLine();

            int i = 0;
            foreach (LivePcapDevice dev in devices)
            {
                Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description);
                i++;
            }

            //选择要监听的网络设备

            Console.WriteLine();
            Console.Write("-- 请选择一个需要监听的网络设备: ");
            i = int.Parse(Console.ReadLine());
            LivePcapDevice device = devices[i];



            Console.Write("-- 请选择操作:监听通讯[C/c],多线程监听通讯[T/t],监听统计[F/f],发送随机数据包[S/s]? ");
            string resp = Console.ReadLine().ToUpper();

            while (!(resp.StartsWith("C") || resp.StartsWith("F") || resp.StartsWith("T") || resp.StartsWith("S")))
            {
                resp = Console.ReadLine().ToUpper();
            }

            try
            {
                if (resp.StartsWith("C") || resp.StartsWith("F") || resp.StartsWith("T"))
                {
                    //监听过滤条件
                    //string filter = "ip and tcp";

                    //连接设备
                    System.Threading.Thread backgroundThread = null;
                    
                    int readTimeoutMilliseconds = 1000;
                    if (resp.StartsWith("F"))
                    {
                        device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
                        //device.SetFilter(filter);
                        device.Mode = CaptureMode.Statistics; //抓包统计
                        device.OnPcapStatistics += new StatisticsModeEventHandler(device_OnPcapStatistics); //抓包统计回调事件

                    }

                    else if (resp.StartsWith("C"))
                    {
                        device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
                        //device.SetFilter(filter);
                        device.Mode = CaptureMode.Packets; //抓数据包
                        showDetails = resp.EndsWith("-A"); //当抓数据包时,检查是否要查看详情

                        device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival); //抓数据包回调事件

                    }

                    else
                    {
                        backgroundThread = new System.Threading.Thread(BackgroundThread);
                        backgroundThread.Start();
                        device.Open();
                       // device.SetFilter(filter);
                        device.Mode = CaptureMode.Packets; //抓数据包
                        showDetails = resp.EndsWith("-A"); //当抓数据包时,检查是否要查看详情
                        device.OnPacketArrival += new PacketArrivalEventHandler(device_OnThreadPacketArrival); //抓数据包回调事件
                    }



                    Console.WriteLine();
                    //Console.WriteLine("-- 当前TCPdump过滤条件: \"{0}\"", filter);
                    Console.WriteLine("-- 正在监听设备 {0}, 按 '回车' 键以停止监听...", device.Description);


                    //开始监听
                    device.StartCapture();

                    //停止监听
                    Console.ReadLine();
                    device.StopCapture();
                    Console.WriteLine("-- 停止监听.");
                    if (backgroundThread != null)
                    {
                        BackgroundThreadStop = true;
                        backgroundThread.Join();
                    }
                }
                else if (resp.StartsWith("S"))
                {
                    //连接设备
                    device.Open();
                    //生成随机数据包
                    byte[] bytes = GetRandomPacket();
                    try
                    {

                        //发送数据
                        device.SendPacket(bytes);
                        SendQueue squeue = new SendQueue(2000);
                        Console.WriteLine("-- 单个数据包发送成功.");

                        for (int j = 0; j < 10; j++)
                        {
                            if (!squeue.Add(bytes))
                            {
                                Console.WriteLine("-- 警告: 队列大小不足以存放所有数据包,将只发送部分数据包.");
                                break;
                            }
                        }
                        device.SendQueue(squeue, SendQueueTransmitModes.Synchronized);
                        Console.WriteLine("-- 数据包队列发送完毕.");
                    }

                    catch (Exception e)
                    {
                        Console.WriteLine("-- " + e.Message);
                    }

                }

            }
            catch (Exception e)
            {
                Console.WriteLine("-- " + e.Message);
            }

            finally
            {
                if (device.Opened)
                {

                    //断开设备连接

                    Console.WriteLine(device.Statistics().ToString());

                    device.Close();

                    Console.WriteLine("-- 断开设备连接.");

                    Console.Write("按 '回车' 键以退出...");

                    Console.Read();

                }

            }

        }



        static bool showDetails = false; //查看详情的参数

        /// <summary>

        /// 抓包方法

        /// </summary>

        private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {

            PcapPorcessContext(e.Packet);

        }



        private static void PcapPorcessContext(PacketDotNet.RawPacket pPacket)
        {

            var time = pPacket.Timeval.Date;
            var len = pPacket.Data.Length;
            var layer = pPacket.LinkLayerType;
            Console.WriteLine("{0}:{1}:{2},{3} Len={4} Layer={5}",
                    time.Hour, time.Minute, time.Second, time.Millisecond, len, layer);


            var packet = PacketDotNet.Packet.ParsePacket(pPacket); //Raw基础包对象
            if (layer == PacketDotNet.LinkLayers.Ethernet) //以太网包
            {
                var ethernetPacket = (PacketDotNet.EthernetPacket)packet;
                System.Net.NetworkInformation.PhysicalAddress srcMac = ethernetPacket.SourceHwAddress;
                System.Net.NetworkInformation.PhysicalAddress destMac = ethernetPacket.DestinationHwAddress;
                Console.WriteLine("MAC:{0} -> {1}", srcMac, destMac);
                if (showDetails) Console.WriteLine("Ethernet packet: " + ethernetPacket.ToColoredString(false));
            }

            var ipPacket = PacketDotNet.IpPacket.GetEncapsulated(packet);  //IP包
            if (ipPacket != null)
            {
                System.Net.IPAddress srcIp = ipPacket.SourceAddress;
                System.Net.IPAddress destIp = ipPacket.DestinationAddress;
                Console.WriteLine("IP: {0} -> {1}", srcIp, destIp);
                if (showDetails) Console.WriteLine("IP packet: " + ipPacket.ToColoredString(false));
                var tcpPacket = PacketDotNet.TcpPacket.GetEncapsulated(packet); //TCP包
                if (tcpPacket != null)
                {
                    int srcPort = tcpPacket.SourcePort;
                    int destPort = tcpPacket.DestinationPort;
                    Console.WriteLine("TCP Port: {0} -> {1}", srcPort, destPort);
                    if (showDetails) Console.WriteLine("TCP packet: " + tcpPacket.ToColoredString(false));
                }
                var udpPacket = PacketDotNet.UdpPacket.GetEncapsulated(packet); //UDP包
                if (udpPacket != null)
                {
                    int srcPort = udpPacket.SourcePort;
                    int destPort = udpPacket.DestinationPort;
                    Console.WriteLine("UDP Port: {0} -> {1}", srcPort, destPort);
                    if (showDetails) Console.WriteLine("UDP packet: " + udpPacket.ToColoredString(false));
                }
            }

        }

        static ulong oldSec = 0;
        static ulong oldUsec = 0;

        /// <summary>
        /// 抓包统计方法
        /// </summary>
        private static void device_OnPcapStatistics(object sender, StatisticsModeEventArgs e)
        {

            // 计算统计心跳间隔
            ulong delay = (e.Statistics.Timeval.Seconds - oldSec) * 1000000 - oldUsec + e.Statistics.Timeval.MicroSeconds;

            // 获取 Bits per second
            ulong bps = ((ulong)e.Statistics.RecievedBytes * 8 * 1000000) / delay;
            /*                                       ^       ^

                                                     |       |

                                                     |       | 

                                                     |       |

                            converts bytes in bits --        |

                                                             |

                        delay is expressed in microseconds --

            */



            // 获取 Packets per second
            ulong pps = ((ulong)e.Statistics.RecievedPackets * 1000000) / delay;

            // 将时间戳装换为易读格式
            var ts = e.Statistics.Timeval.Date.ToLongTimeString();



            // 输出统计结果
            Console.WriteLine("{0}: bps={1}, pps={2}", ts, bps, pps);



            //记录本次统计时间戳,以用于下次统计计算心跳间隔

            oldSec = e.Statistics.Timeval.Seconds;

            oldUsec = e.Statistics.Timeval.MicroSeconds;

        }


        /// <summary>

        /// 生成一个大小为200的随机数据包

        /// </summary>
        private static byte[] GetRandomPacket()
        {

            byte[] packet = new byte[200];

            Random rand = new Random();

            rand.NextBytes(packet);

            return packet;

        }

        /// <summary>

        /// 生成一个大小为98的数据包

        /// </summary>
        private static byte[] GetPacket()
        {

            byte[] packet = new byte[]

            {

                0x00,0x02,0x65,0x11,0xa6,0x05,                     //srcMac

                0x00,0x1b,0x38,0xa5,0xc2,0x40,                     //destMac

                0x08,0x00,                                         //Type Ip

                0x45,                                              //Version 4

                0x00,                                              //Differentiated Services Field 分隔符

                0x00,0x54,                                         //Total Length 84

                0x43,0x08,                                         //Identification 校验位

                0x40,0x00,                                         //Fragment offset 片偏移

                0x80,                                              //Time to live 生存时间

                0x06,                                              //Protocol TCP

                0x40,0x00,                                         //Header checksum 报头校验和

                0xc0,0xa8,0x00,0x71,                               //srcIP

                0xc0,0xa8,0x00,0x6a,                               //destIP

                0x26,0x8e,                                         //srcPort

                0x04,0x04,                                         //destPort

                0x5b,0x0c,0x5e,0xc7,                               //Sequence number 序号

                0xca,0xf9,0x1b,0xb1,                               //Acknowledgement number 应答号

                0x80,                                              //Header Length 32

                0x18,                                              //Flags [PSH,ACK]

                0x41,0x10,                                         //Window size

                0x82,0x72,                                         //Checksum 校验和

                0x01,                                              //Options NOP

                0x01,                                              //Options NOP

                0x08,0x0a,0x00,0x00,0xac,0x4c,0x00,0x41,0x50,0xaa, //Options Timestamps

                0x21,                                              //Data Start 这之后是我这个项目中的服务器和终端通讯的特有的附加数据

                0x0a,                                              //Command

                0x00,0x00,                                         //CID

                0x01,0x00,0x00,0x00,                               //TID

                0x00,0x00,0x00,0x00,                               //Param1

                0x00,0x00,0x00,0x00,                               //Param2

                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,           //Param3

                0x30,0x30,0x30,0x30,                               //ErrorCode

                0x00,0x00,0xec,0x00                                //ExtraData

            };

            return packet;

        }

        private static DateTime LastStatisticsOutput = DateTime.Now;
        private static TimeSpan LastStatisticsInterval = new TimeSpan(0, 0, 2);
        private static void device_OnThreadPacketArrival(object sender, CaptureEventArgs e)
        {

            //输出设备通讯统计信息

            var Now = DateTime.Now;

            var interval = Now - LastStatisticsOutput;

            if (interval > LastStatisticsInterval)
            {

                Console.WriteLine("Device Statistics: " + ((LivePcapDevice)e.Device).Statistics());

                LastStatisticsOutput = Now;

            }



            lock (QueueLock)
            {

                PacketQueue.Add(e.Packet); //将捕获到的数据包加入处理队列

            }

        }

        /// <summary>

        /// 多线程处理数据包队列

        /// </summary>
        private static void BackgroundThread()
        {

            while (!BackgroundThreadStop)
            {

                bool shouldSleep = true;



                lock (QueueLock)
                {

                    if (PacketQueue.Count != 0)
                    {

                        shouldSleep = false;

                    }

                }



                if (shouldSleep)
                {

                    System.Threading.Thread.Sleep(250);

                }

                else //处理队列
                {

                    List<PacketDotNet.RawPacket> ourQueue; //本线程待处理队列

                    lock (QueueLock)
                    {

                        ourQueue = PacketQueue;

                        PacketQueue = new List<PacketDotNet.RawPacket>();

                    }



                    Console.WriteLine("BackgroundThread: Local Queue Count is {0}", ourQueue.Count);



                    foreach (var packet in ourQueue)
                    {

                        PcapPorcessContext(packet);

                    }

                }

            }

        }
        private static bool BackgroundThreadStop = false; //线程停止标识
        private static object QueueLock = new object(); //线程锁变量
        private static List<PacketDotNet.RawPacket> PacketQueue = new List<PacketDotNet.RawPacket>(); //待处理数据包队列


    }

}

 

posted @ 2012-07-17 15:27  科爷  阅读(711)  评论(1编辑  收藏  举报