0

我有一个允许用户扫描网络的 GUI 程序,问题是当调用 pcap_loop 函数时,我的 GUI 程序变得无响应。(pcap_loop 阻塞了当前线程)。

当我尝试使用 pthreads 时,我在 pcap_loop 函数处遇到了 SIGSEGV 错误。为什么?就好像线程看不到 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.
4

2 回答 2

3

我强烈建议不要使用线程,除非你绝对必须这样做。

问题是您必须非常小心以避免竞争条件和其他同步问题。例如,您的 GUI 框架库可能不希望从多个线程中调用,因此您的//show packets here例程可能会使它很困惑。

相反,如果可能的话,我建议从主线程读取数据包。你没有说你使用的是哪个 GUI 框架;因为您使用的是 C++,所以我会假设 Qt,因为这很常见,但所有其他框架都具有类似的功能。

你需要做的是:

  • 调用 pcap_setnonblock() 将捕获描述符置于非阻塞模式
  • 调用 pcap_get_selectable_fd() 以获取文件描述符以监视事件
  • 使用QSocketNotifier对象(将上一步中的文件描述符作为套接字参数传递)来监视文件描述符中的事件
  • 当事件触发时,调用 pcap_dispatch() 来分派数据包
  • 为了获得最大的可移植性,还要在计时器上调用 pcap_dispatch(),因为 select() 在某些操作系统上的 pcap 套接字上不能很好地工作。

(至于您的代码当前崩溃的原因 - 请注意,您可能想要传递handler而不是&handler作为参数传递给pthread_create(). 但只是修复它可能会导致以后奇怪的不可靠性 - 所以单线程几乎肯定是前进的方向!)

于 2011-01-01T11:46:54.380 回答
1

你需要更少的“&”。假设

pcap_t *handle = pcap_open_live(...);

using&handle将是 type pcap_t **,但是您的线程函数将其强制转换回(顺便说一下,强制转换也是无意义/冗余的)pcap_t *,这会导致使用它时出现未定义的行为,并且通常会出错。更好的:

静态 void *pcap_looper(void *arg)
{
        pcap_t *句柄 = arg;

        /* ETC。 */

        返回空值;
}

诠释主要(无效)
{
        pcap_t *句柄;
        pthread_t tid;
        诠释;

        句柄 = pcap_open_live(...);
        ret = pthread_create(&tid, NULL, pcap_looper, 句柄);
        ...
        pthread_join(tid, NULL);
        返回 EXIT_SUCCESS;
}
于 2011-01-01T11:42:57.047 回答