2011-10-14 13 views
6

Estoy tratando de escribir una aplicación que busca constantemente el host en una LAN. Cuando ejecuto esto como una consola como la cuenta atrás. Esperar() parece funcionar bien. Sin embargo, cuando introduzco el código en una ventana, aparece la cuenta regresiva. Signal() no parece disminuir su contador. No estoy seguro de cual es el problema.Código asíncrono que funciona en la consola pero no en Windows Forms

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Net.NetworkInformation; 
using System.Diagnostics; 
using System.Net; 
using System.Threading; 

namespace Multi_Threaded 
{ 
    public partial class Form1 : Form 
    { 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     PortScanner ps = new PortScanner(); 
     ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted); 

     ps.run_ping_probe(); 
    } 

    void ps_ProbeCompleted(object sender, PingProbeCompletedArguments e) 
    { 
     MessageBox.Show("I found " + e.ip_adresses_list_of_host.Count.ToString() + "host(s)"); 
    } 
} 

public delegate void PingProbeCompleted(object sender,PingProbeCompletedArguments e); 
public class PingProbeCompletedArguments : EventArgs 
{ 
    public List<string> ip_adresses_list_of_host; 
} 
public class PortScanner 
{ 
    public event PingProbeCompleted ProbeCompleted; 
    static List<string> ip_adresses = new List<string>(); 

    static CountdownEvent countdown; 

    public void run_ping_probe() 
    { 
     ip_adresses.Clear(); 

     countdown = new CountdownEvent(1); 

     string ipBase = "10.125."; 
     for (int sub = 0; sub < 14; sub++) 
     { 
      for (int i = 1; i < 255; i++) 
      { 
       string ip = ipBase + sub.ToString() + "." + i.ToString(); 
       Ping p = new Ping(); 
       p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted); 
       countdown.AddCount(); 
       p.SendAsync(ip, 100, ip); 
      } 
     } 
     countdown.Signal(); 
     countdown.Wait(); 
     PingProbeCompletedArguments e = new PingProbeCompletedArguments(); 
     e.ip_adresses_list_of_host = ip_adresses; 
     ProbeCompleted(this, e); 

    } 

    private void p_PingCompleted(object sender, PingCompletedEventArgs e) 
    { 
     string ip = (string)e.UserState; 
     if (e.Reply.Status == IPStatus.Success) 
     { 
      ip_adresses.Add(ip + "\t" + e.Reply.RoundtripTime + " ms"); 
     } 
     countdown.Signal(); 
    } 
} 

Respuesta

0

your wait handler se ejecuta bajo un subproceso de threadpool. que necesita para obtener de nuevo en el hilo de interfaz de usuario que ha actualizado la interfaz de usuario (debido al bucle de mensajes que la interfaz de usuario se ejecuta en) - para que utilice SynchronizationContext

Aquí más información sobre la manera de que ella: http://www.codeproject.com/KB/threads/SynchronizationContext.aspx

6

Sí, bloquea el código cuando lo usa en un proyecto de Winforms. El problema es que la clase Ping hace un gran esfuerzo para generar el evento PingCompleted en el mismo subproceso que llamó SendAsync(). Utiliza el método AsyncOperationManager.CreateOperation() para hacerlo.

El problema es que realmente funciona en una aplicación de Winforms. Intenta elevar el evento en el hilo principal. Pero eso no puede funcionar ya que bloqueó el hilo principal con la llamada countdown.Wait(). El ping no puede completarse debido a que el hilo principal está bloqueado. El hilo principal no puede completarse ya que el ping no se completa. Ciudad sin salida.

Funciona en una aplicación de modo consola ya que no tiene un proveedor de sincronización como lo hace Winforms. El evento PingComplete se generará en una secuencia de subprocesos.

El bloqueo del hilo de la interfaz de usuario es fundamentalmente defectuoso. La solución rápida es ejecutar el código en un hilo de trabajo. Tenga en cuenta que esto hace que el evento ProbeCompleted también se active en ese trabajador. Use Control.BeginInvoke() para calcular el hilo de la interfaz de usuario. O use BackgroundWorker.

private void Form1_Load(object sender, EventArgs e) { 
     PortScanner ps = new PortScanner(); 
     ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted); 
     ThreadPool.QueueUserWorkItem((w) => ps.run_ping_probe()); 
    } 

Y no olvide quitar la llamada adicional de Signal().

Cuestiones relacionadas