为了让程序更好地工作,需要解决进程阻塞问题,因为程序阻塞后,将一直等待Trap的到来,在没有接收到Trap前,程序将不响应任何消息。这对我们来说是不能忍受的。解决的办法是采用多线程技术,即开始接收trap时,启动另一个线程专门用来接收trap,而程序界面不至于被“冻结”。
启动与关闭trap监听
void CSnmpMgrDlg::OnTrap() //onTrap是按钮的相应处理
{
CButton *pBt;
pBt=(CButton *)GetDlgItem(IDC_TRAP);
if(m_bRecvTrap==false)
{
if(pSnmp.sessionID==FALSE)
{
pSnmp.CreateSession(CSnmpMgrDlg::m_hWnd,wMsg);
pSnmp.sessionID=TRUE;
}
m_bRecvTrap=true;
AfxBeginThread(WorkerThreadProc,this,THREAD_PRIORITY_NORMAL,0,0,NULL); ///创建线程, 线程函数为WorkerThreadProc 参数为this指针。
pBt->SetWindowText("停止接收陷阱"); //修改按钮文字
}
else
{
m_bRecvTrap=false;
Snmp::socket_startup();
UdpAddress address("127.0.0.1:162");
int status;
Snmp snmp(status, 0) ;
Pdu pdu;
pdu.set_notify_id("1.3.6.1");
pdu.set_notify_enterprise( "test");
CTarget ctarget(address);
ctarget.set_version( version1);
ctarget.set_readcommunity("public");
SnmpTarget *target=&ctarget;
status = snmp.trap(pdu,*target); //向本机发送Trap以标志退出监听。
Snmp::socket_cleanup();
pBt->SetWindowText("开始接收陷阱");
}
}
线程函数的实现。线程函数是一个全局函数。
UINT WorkerThreadProc(LPVOID Param)
{
CSnmpMgrDlg *pCV;
pCV=(CSnmpMgrDlg *)Param; //将指针类型转换为CSnmpMgrDlg *类型指针;
int trap_port=162; //指定监听端口号;
OidCollection oidc;
TargetCollection targetc; //创建过滤TRAP的对象;
CNotifyEventQueue::set_listen_port(trap_port); //设置端口号;
int status;
Snmp::socket_startup();
Snmp *snmp = new Snmp(status, 0); // 创建Snmp对象;
if ( status != SNMP_CLASS_SUCCESS)
{
AfxMessageBox("出现错误!");
return TRUE;
}
status=snmp->notify_register(oidc, targetc,callme,Param);
if (status != SNMP_CLASS_SUCCESS)
{
AfxMessageBox("出现错误!");
return TRUE;
}
while(pCV->m_bRecvTrap)
snmp->eventListHolder->SNMPProcessEvents();//进入SNMPProcessEvents()函数,等待TRAP触发回调用函数;
Snmp::socket_cleanup();
AfxMessageBox("已停止!");
return TRUE;
}
回调函数,用来处理接收到的trap
void callme (int reason, Snmp *snmp, Pdu &pdu, SnmpTarget &target, void *cd)
{
CString str="";
CTime time=CTime::GetCurrentTime();
CString time_str=time.Format("%Y-%m-%d:%H:%M:%S"); //计算接收的时间
CSnmpMgrDlg *p;
p=(CSnmpMgrDlg *)cd;
Vb nextVb;
GenAddress addr;
target.get_address(addr);
IpAddress from(addr);
CString ipadd=from.get_printable(); //获取ip地址
if (ipadd=="127.0.0.1")
return; //结束监听时本机发送的TRAP退出循环,不做任何处理;
Oid id,ent;
pdu.get_notify_id(id);
pdu.get_notify_enterprise(ent);
CString TrapId=id.get_printable(); //获取Trap id
CString EnterPrise=ent.get_printable(); //获取 Enterprise
CString index,name;
pdu.get_vb(nextVb, 0);
index=nextVb.get_printable_value(); //获取被管对象索引值
pdu.get_vb(nextVb, 1);
name=nextVb.get_printable_value(); //获取被管对象名称
///此处处理并显示给用户数据
}