2011-01-01 14 views
0

Ich habe ein GUI-Programm, mit dem ein Benutzer ein Netzwerk scannen kann, das Problem ist, dass, wenn die pcap_loop -Funktion aufgerufen wird, mein GUI-Programm nicht mehr reagiert (die pcap_loop blockiert den aktuellen Thread).Threading und pcap Probleme

Wenn ich versuche, pthreads zu verwenden, bekam ich einen SIGSEGV-Fehler an der pcap_loop-Funktion.Warum? Es ist, als ob der Thread die procPacket-Funktion selbst nicht sehen kann.

void procPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet) 
{ 
    //show packets here 
} 
void* pcapLooper(void* param) 
{ 
    pcap_t* handler = (pcap_t*) param; 
    pcap_loop(handler, 900 ,procPacket, NULL); 

} 
    //some function that runs when a button is pressed 
    //handler has been opened through pcap_open_live 
    pthread_t scanner; 
    int t = pthread_create(&scanner,NULL,&pcapLooper, &handler); 
    if(t) 
    { 
     std::cout << "failed" << std::endl; 
    } 
    pthread_join(scanner,NULL); 
    //do other stuff. 

Antwort

1

Sie brauchen viel weniger "&" s. Unter der Annahme,

 
pcap_t *handle = pcap_open_live(...); 

&handle Verwendung wird vom Typ pcap_t **, aber Thread-Funktion wirft es zurück (die Besetzung durch die Art und Weise ist auch sinnlos/redundant) zu pcap_t *, was zu undefiniertem Verhalten führt, wenn es verwendet wird, und ist in der Regel wird schief gehen. Besser:

 
static void *pcap_looper(void *arg) 
{ 
     pcap_t *handle = arg; 

     /* etc. */ 

     return NULL; 
} 

int main(void) 
{ 
     pcap_t *handle; 
     pthread_t tid; 
     int ret; 

     handle = pcap_open_live(...); 
     ret = pthread_create(&tid, NULL, pcap_looper, handle); 
     ... 
     pthread_join(tid, NULL); 
     return EXIT_SUCCESS; 
} 
3

Ich würde dringend vorschlagen, keine Threads zu verwenden, es sei denn, Sie müssen unbedingt.

Das Problem ist, dass Sie sehr vorsichtig sein müssen, um Race Conditions und andere Synchronisationsprobleme zu vermeiden. Zum Beispiel erwartet Ihre GUI-Framework-Bibliothek wahrscheinlich nicht, von mehreren Threads aufgerufen zu werden, und so kann Ihre //show packets here-Routine es oft verwirren.

Stattdessen würde ich vorschlagen, wenn möglich, die Pakete aus dem Hauptthread zu lesen. Sie sagen nicht, welches GUI-Framework Sie verwenden; Da Sie C++ verwenden, nehme ich Qt an, da das ziemlich häufig ist, aber alle anderen Frameworks haben ähnliche Funktionen.

Was Sie tun müssen, ist:

  • Anruf pcap_setnonblock() in nicht-blockierenden Modus die Capture-Descriptor zu setzen
  • Anruf pcap_get_selectable_fd() einen Dateideskriptor zu erhalten für Ereignisse zu überwachen
  • Verwenden Sie ein QSocketNotifier-Objekt (übergeben Sie den Dateideskriptor aus dem vorherigen Schritt als Socketparameter), um den Dateideskriptor für Ereignisse zu überwachen
  • Wenn das Ereignis ausgelöst wird, rufen Sie pcap_dispatch() auf, um Pakete
  • zu senden
  • Für maximale Portabilität rufen Sie auch pcap_dispatch() für einen Timer auf, da select() auf einigen Betriebssystemen nicht gut auf pcap Sockets funktioniert.

(Wie, warum gerade Ihr Code abstürzt - beachten Sie, dass Sie wahrscheinlich handler anstatt &handler als Parameter an pthread_create() übergeben wollen aber Fixierung nur, dass später zu seltsamen Unzuverlässigkeit führen kann -. So gehen Single-Threaded ist fast sicher der Weg nach vorne!)