C# SharpPCap 크로스 스레드 작업이 유효하지 않습니다
문제
안녕하세요 샤프 캡에서 example3에서 패킷 캡처를 변환하려고합니다. 새 버전 SharpPCap-2.2.0rc1.src에서 콘솔 응용 프로그램에서 Windows Forms 응용 프로그램으로.
패킷을 추가하려고 할 때 문제에 직면 해 있습니다. ListView Control에 캡처되었을 때 다음과 같은 오류가 발생합니다.
(크로스 스레드 작업 유효하지 않음 : 제어 'ListViewPackets'가 생성 된 스레드 이외의 스레드에서 액세스했습니다.)
이 라인에서 :
listViewPackets.Items.Add(e.Packet.ToString());
이 문제를 해결하기위한 조언이 있습니까 ???
내 코드는 다음과 같습니다.
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());
}
}
}
............................................................................................................................................................. ................... 여기에 원래 코드는 다음과 같습니다.
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());
}
}
}
해결책
다른 스레드에서 컨트롤을 호출 할 때 :
if (listView1.InvokeRequired)
{
listView1.BeginInvoke(new MethodInvoker(
() => /*whatever you want with listview */));
}
else
{
/* whatever you want with listview */
}
항상 다른 스레드에있을 것이라는 것을 알고 있다면 IF/Else를 잊어 버리고 호출을 사용하십시오.
편집하다:
따라서 귀하의 경우에는 다음과 같습니다.
if(listView1.InvokeRequired)
{
listView1.BeginInvoke(new MethodInvoker(
() => listViewPackets.Items.Add(e.Packet.ToString()) ));
}
else
{
listViewPackets.Items.Add(e.Packet.ToString());
}
(다시, 또는 항상 다른 스레드에서 실행되는 경우, Beartinvoke 호출만으로)
편집 2 Shane은 Invoke를 사용하고 BeginInvoke를 사용한다는 것을 알 수 있습니다. 나는 그것을 습관의 힘으로 사용합니다. invoke를 사용하면 UI 스레드가 차단되며, 더 오래 걸리는 작업을 수행하는 경우 BeginInvoke를 사용하면 UI를 비동기로 업데이트합니다.
다른 팁
사용해야합니다 부르다 패킷이 다른 스레드에 들어 오기 때문에. UI 컨트롤은 생성 된 것 이외의 스레드에서 수정할 수 없습니다. Invoke는 UI 스레드에서 주어진 대의원을 실행합니다. 예를 들어,이를 수행 할 수 있습니다.
this.Invoke(new MethodInvoker(() => listViewPackets.Items.Add(e.Packet.ToString())), null);