我有两个线程,每个线程同时从同一个deviсe捕获数据包,但是当第二个线程到达pcap_compile()
函数时程序崩溃。此外,每个线程都有自己的变量,不使用全局变量。看起来他们获得了相同的设备句柄,因此程序崩溃了。为什么我需要两个线程?因为我想在已发送的和由指定的pcap
过滤器接收的数据包上分离数据包。那么我该如何解决这个问题呢?或者,使用一个线程并使用tcp
标题中的地址手动对发送和接收的数据包进行排序更好?
答案 0 :(得分:2)
pcap_compile 不线程安全。您必须包含对具有临界区/互斥锁的单独线程可能遇到的所有调用,以防止错误,因为解析器中编译表达式的非线程安全状态(对于血淋淋的细节,它使用YACC创建代码解析表达式并为其生成的代码显然不是线程安全的。)
您需要为每次计划用于捕获的线程明确地打开设备一次,如果您在多个线程中重复使用相同的设备句柄,那么它将无法满足您的要求。您应该在您计划使用它的线程中打开pcap句柄,因此计划捕获的每个线程都应该自己执行pcap_open
。
使用Critical Section来保护对pcap_compile
的调用,你可以创建一个简单的包装器(Windows关键部分的C ++包装器):
class lock_interface {
public:
virtual void lock() = 0;
virtual void unlock() = 0;
};
class cs : public lock_interface {
CRITICAL_SECTION crit;
public:
cs() { InitializeCriticalSection(&crit); }
~cs() { DeleteCriticalSection(&crit); }
virtual void lock() {
EnterCriticalSection(&crit);
}
virtual void unlock() {
LeaveCriticalSection(&crit);
}
private:
cs(const locker &);
cs &operator=(const cs &);
};
class locker {
lock_interface &m_ref;
public:
locker(lock_interface &ref) : m_ref(ref) { m_ref.lock(); }
~locker() { m_ref.unlock(); }
private:
locker(const locker &);
locker &operator=(const locker &);
};
static cs section;
int
wrapped_pcap_compile(pcap_t *p, struct bpf_program *fp, const char *str, int optimize, bpf_u_int32 netmask)
{
locker locked(section);
pcap_compile(p, fp, str, optimize, netmask);
}
答案 1 :(得分:1)
如果您使用的是C ++ 11,则可能会有类似的内容:
int thread_safe_pcap_compile_nopcap(int snap_len, int link_type,
struct bpf_program *fp, char const *str,
int optimize, bpf_u_int32 netmask) {
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
return pcap_compile_nopcap(snap_len, link_type, fp, str, optimize, netmask);
}
与pcap_compile
函数相似。