Проблемы с потоками и pcap - PullRequest
0 голосов
/ 01 января 2011

У меня есть программа с графическим интерфейсом, которая позволяет пользователю сканировать сеть, проблема в том, что при вызове функции pcap_loop моя программа с графическим интерфейсом перестает отвечать на запросы (pcap_loop блокирует текущий поток).

Когдая пытаюсь использовать pthreads, я получил ошибку SIGSEGV в функции pcap_loop. Почему? Это как если бы поток не мог видеть саму функцию procPacket.

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.

Ответы [ 2 ]

3 голосов
/ 01 января 2011

Я бы настоятельно рекомендовал не использовать потоки, если вам это абсолютно не нужно.

Проблема в том, что вы должны быть предельно осторожны, чтобы избежать условий гонки и других проблем с синхронизацией. Например, ваша библиотека фреймворка с графическим интерфейсом, вероятно, не ожидает вызова из нескольких потоков, поэтому ваша подпрограмма //show packets here может сильно ее запутать.

Вместо этого я бы предложил, если это возможно, читать пакеты из основного потока. Вы не говорите, какой графический интерфейс вы используете; так как вы используете C ++, я предполагаю, что Qt довольно распространен, но все остальные фреймворки имеют схожую функциональность.

Что вам нужно сделать, это:

  • Вызовите pcap_setnonblock (), чтобы перевести дескриптор захвата в неблокирующий режим
  • Вызовите pcap_get_selectable_fd (), чтобы получить дескриптор файла для отслеживания событий
  • Используйте объект QSocketNotifier (передавая дескриптор файла из предыдущего шага в качестве параметра сокета), чтобы отслеживать дескриптор файла на наличие событий
  • Когда происходит событие, вызовите pcap_dispatch () для отправки пакетов
  • Для максимальной переносимости также вызовите pcap_dispatch () для таймера, потому что select () плохо работает на сокетах pcap в некоторых ОС.

(Относительно того, почему ваш код в настоящее время дает сбой - обратите внимание, что вы, вероятно, хотите передать handler вместо &handler в качестве параметра pthread_create(). Но только исправление, которое может привести к странной ненадежности позже - так что одиночный - почти наверняка путь вперед!)

1 голос
/ 01 января 2011

Вам нужно гораздо меньше "&". Предполагая

pcap_t *handle = pcap_open_live(...);

с использованием &handle будет иметь тип pcap_t **, но ваша функция потока возвращает его (преобразование, кстати, также бессмысленно / избыточно) к pcap_t *, что приводит к неопределенному поведению при его использовании, и является обычно идет не так Лучше:

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;
}
...