线程和 pcap 问题

发布于 2024-10-10 08:55:39 字数 760 浏览 7 评论 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.

I have a GUI program that allows a user a scan a network, the issue is that when the pcap_loop function is called, my GUI program becomes unresponsive.(the pcap_loop blocks the current thread).

When i try to use pthreads, i got a SIGSEGV fault at the pcap_loop function.Why?It's as if the thread can't see the procPacket function itself.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

平定天下 2024-10-17 08:55:39

我强烈建议不要使用线程,除非绝对必要。

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

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

您需要做的是:

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

(至于为什么您的代码当前崩溃 - 请注意,您可能希望将 handler 而不是 &handler 作为参数传递给 pthread_create()。但是仅仅解决这个问题可能会导致以后出现奇怪的不可靠性 - 所以单线程几乎肯定是前进的方向!)

I would strongly suggest not using threads unless you absolutely have to.

The problem is that you have to be extremely careful to avoid race conditions and other synchronisation problems. For instance, your GUI framework library is probably not expecting to be called from multiple threads, and so your //show packets here routine may confuse it a lot.

Instead I would suggest, if possible, reading the packets from the main thread. You don't say which GUI framework you're using; since you're using C++ I'll assume Qt since that's quite common, but all other frameworks have similar functionality.

What you need to do is:

  • Call pcap_setnonblock() to put the capture descriptor in non-blocking mode
  • Call pcap_get_selectable_fd() to get a file descriptor to monitor for events
  • Use a QSocketNotifier object (passing the file descriptor from the previous step as the socket parameter) to monitor the file descriptor for events
  • When the event fires, call pcap_dispatch() to dispatch packets
  • For maximum portability, also call pcap_dispatch() on a timer, because select() doesn't work well on pcap sockets on some OSs.

(As to why your code is currently crashing - note that you probably want to pass handler rather than &handler as the parameter to pthread_create(). But just fixing that may lead to strange unreliability later - so going single-threaded is almost certainly the way forward!)

誰認得朕 2024-10-17 08:55:39

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

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

You need much less "&"s. Assuming

pcap_t *handle = pcap_open_live(...);

using &handle will be of type pcap_t **, but your thread function casts it back (the cast by the way is also pointless/redundant) to pcap_t *, which leads to undefined behavior when using it, and is usually going to go wrong. Better:

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文