简体   繁体   English

C#SharpPcap跨线程操作无效

[英]C# SharpPcap Cross-thread operation not valid

Hi I'm trying to convert packet capturing in Example3 in SharpPcap new version SharpPcap-2.2.0rc1.src from Console Application to Windows Forms Application. 嗨,我正在尝试将SharpPcap新版本SharpPcap-2.2.0rc1.src中Example3中的数据包捕获从控制台应用程序转换为Windows窗体应用程序。

I'm facing a problem when I tried to add packets has been captured to ListView control I will get an error which is: 当我尝试将数据包添加到ListView控件时,我遇到了一个问题,我将收到一个错误消息:

(Cross-thread operation not valid: Control 'listViewPackets' accessed from a thread other than the thread it was created on.) (跨线程操作无效:控制“ listViewPackets”是从创建该线程的线程之外的线程访问的。)

at this line: 在这一行:
listViewPackets.Items.Add(e.Packet.ToString());

any Advice to solve this problem??? 任何建议来解决这个问题???

here is my code: 这是我的代码:

using SharpPcap;

namespace Packets
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }



            // Retrieve the device list

        private void btnLiDevicest_Click(object sender, EventArgs e)
        {
            var devices = LivePcapDeviceList.Instance;
            // If no devices were found print an error
            if (devices.Count < 1)
            {
                MessageBox.Show("No devices were found on this machine");
                return;
            }


            int i = 0;

            // Print out the devices
            foreach (LivePcapDevice dev in devices)
            {

                ///* Description */
                //Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description);
                cmbListDevice.Items.Add(dev.Name + "   " + dev.Description);
                i++;
            }
           LivePcapDevice device = devices[1];
            // Register our handler function to the 'packet arrival' event
            device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival);

            // Open the device for capturing
            int readTimeoutMilliseconds = 1000;
            device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
            device.StartCapture();


        }


            //Console.WriteLine();
            //Console.WriteLine("-- Listening on {0}, hit 'Enter' to stop...",
            //    device.Description);
                    /// <summary>
        /// Prints the time and length of each received packet
        /// </summary>
        /// 

        protected  void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            DateTime time = e.Packet.PcapHeader.Date;
            uint len = e.Packet.PcapHeader.PacketLength;
            //Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 
            //    time.Hour, time.Minute, time.Second, time.Millisecond, len);

           // Console.WriteLine(e.Packet.ToString());

            listViewPackets.Items.Add(e.Packet.ToString());


        }



        }


}

................................. .................................... here is the original code: .................................. ................. ..........这是原始代码:

using System;
using System.Collections.Generic;
using SharpPcap;
namespace SharpPcap.Test.Example3
{
    /// <summary>
    /// Basic capture example
    /// </summary>
    public class BasicCap
    {
        public static void Main(string[] args)
        {
            // Print SharpPcap version
            string ver = SharpPcap.Version.VersionString;
            Console.WriteLine("SharpPcap {0}, Example3.BasicCap.cs", ver);

            // Retrieve the device list
            var devices = LivePcapDeviceList.Instance;

            // If no devices were found print an error
            if(devices.Count < 1)
            {
                Console.WriteLine("No devices were found on this machine");
                return;
            }

            Console.WriteLine();
            Console.WriteLine("The following devices are available on this machine:");
            Console.WriteLine("----------------------------------------------------");
            Console.WriteLine();

            int i = 0;

            // Print out the devices
            foreach(LivePcapDevice dev in devices)
            {
                /* Description */
                Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description);
                i++;
            }

            Console.WriteLine();
            Console.Write("-- Please choose a device to capture: ");
            i = int.Parse( Console.ReadLine() );

            LivePcapDevice device = devices[i];

            // Register our handler function to the 'packet arrival' event
            device.OnPacketArrival += 
                new PacketArrivalEventHandler( device_OnPacketArrival );

            // Open the device for capturing
            int readTimeoutMilliseconds = 1000;
            device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);

            Console.WriteLine();
            Console.WriteLine("-- Listening on {0}, hit 'Enter' to stop...",
                device.Description);

            // Start the capturing process
            device.StartCapture();

            // Wait for 'Enter' from the user.
            Console.ReadLine();

            // Stop the capturing process
            device.StopCapture();

            Console.WriteLine("-- Capture stopped.");

            // Print out the device statistics
            Console.WriteLine(device.Statistics().ToString());

            // Close the pcap device
            device.Close();
        }

        /// <summary>
        /// Prints the time and length of each received packet
        /// </summary>
        private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            DateTime time = e.Packet.PcapHeader.Date;
            uint len = e.Packet.PcapHeader.PacketLength;
            Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 
                time.Hour, time.Minute, time.Second, time.Millisecond, len);
            Console.WriteLine(e.Packet.ToString());
        }
    }
}

When making a call to a control from another thread: 从另一个线程调用控件时:

if (listView1.InvokeRequired)
{
    listView1.BeginInvoke(new MethodInvoker(
        () => /*whatever you want with listview */));
}
else
{
    /* whatever you want with listview */
}

If you know for sure that it will always be on another thread, then just forget the if/else and use the invoke. 如果您确定它将始终在另一个线程上,则只需忘记if / else并使用调用。

EDIT: 编辑:

so in your case, it'd look like: 因此,在您的情况下,它看起来像:

if(listView1.InvokeRequired)
{
    listView1.BeginInvoke(new MethodInvoker(
        () => listViewPackets.Items.Add(e.Packet.ToString()) ));
}
else
{
    listViewPackets.Items.Add(e.Packet.ToString());
}

(again, or just the BeginInvoke call, if it will always run on a different thread) (再次,或者只是BeginInvoke调用,如果它将始终在其他线程上运行)

EDIT 2 You'll notice that Shane uses Invoke and I use BeginInvoke. 编辑2您会注意到Shane使用Invoke,而我使用BeginInvoke。 I use it as a force of habit. 我用它来养成习惯。 Using Invoke will block on the UI thread, and if you're performing an operation that takes longer, using BeginInvoke performs the update to the UI asynchronously. 使用Invoke将阻塞UI线程,并且如果您执行的操作花费的时间更长,则使用BeginInvoke异步执行对UI的更新。

You need to use Invoke because the packet is coming in on a different thread. 您需要使用Invoke,因为数据包是从另一个线程进入的。 UI controls cannot be modified on a thread other than the one they're created on. UI控件只能在创建线程的线程之外进行修改。 Invoke will execute the given delegate on the UI thread. 调用将在UI线程上执行给定的委托。 For example, you could do this: 例如,您可以这样做:

this.Invoke(new MethodInvoker(() => listViewPackets.Items.Add(e.Packet.ToString())), null);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM