我們正在Delphi XE5中開發一個程序來監視本地網絡中的MFP。對於每個傳入的SNMP陷阱通知,我們能夠確定發送它的MFP是非常重要的。似乎TIdSNMP.ReceiveTrap將自上次調用以來收到的每個通知放入TIdSNMP.Trap.Value數組屬性的元素中; TIdSNMP.Trap.Host包含發送最新陷阱通知的MFP的IP地址。有人可以證實這一點嗎?有什麼方法可以獲得對應於TIdSNMP.Trap.Value其他元素的IP地址嗎?如何使用TIdSNMP從多個來源接收陷阱通知
出於測試目的,我們使用下面的代碼來接收和顯示SNMP陷阱消息:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
IdBaseComponent, IdComponent, IdUDPBase, IdUDPClient, IdSNMP;
type
TForm1 = class(TForm)
Button2: TButton;
IdSNMP1: TIdSNMP;
Memo1: TMemo;
procedure Button2Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button2Click(Sender: TObject);
procedure FormatTrap(ASnmpInfo : TSnmpInfo);
var
i : integer;
begin
Memo1.Lines.Add('{');
with ASnmpInfo do begin
Memo1.Lines.Add(Format('Host=%s, ', [Host]));
Memo1.Lines.Add(Format('Port=%d, ', [Port]));
Memo1.Lines.Add(Format('Enterprise=%s, ', [Enterprise]));
Memo1.Lines.Add(Format('GenTrap=%d, ', [GenTrap]));
Memo1.Lines.Add(Format('SpecTrap=%d, ', [SpecTrap]));
Memo1.Lines.Add(Format('Version=%d, ', [Version]));
Memo1.Lines.Add(Format('PDUType=%d, ', [PDUType]));
Memo1.Lines.Add(Format('TimeTicks=%d, ', [TimeTicks]));
Memo1.Lines.Add(Format('ID=%d, ', [ID]));
Memo1.Lines.Add(Format('ErrorStatus=%d, ', [ErrorStatus]));
Memo1.Lines.Add(Format('ErrorIndex=%d, ', [ErrorIndex]));
Memo1.Lines.Add(Format('Community=%s, ', [Community]));
Memo1.Lines.Add(Format('ValueCount=%d, ', [ValueCount]));
for i := 0 to ValueCount-1 do begin
Memo1.Lines.Add(Format('Value[%d]=%s, ', [i,Value[i]]));
Memo1.Lines.Add(Format('ValueOID[%d]=%s, ', [i,ValueOID[i]]));
Memo1.Lines.Add(Format('ValueType[%d]=%d, ', [i,ValueType[i]]));
end;
Memo1.Lines.Add('}');
end;
end;
begin
while not Application.Terminated do begin
if IdSNMP1.ReceiveTrap() then begin
FormatTrap(IdSNMP1.Trap);
end;
Sleep(100);
Application.ProcessMessages();
end;
end;
end.
兩個MFP - 一個柯尼卡美能達BIZHUB C364e 192.168.197.159下和192.168下柯尼卡美能達BIZHUB C364。 197.19 - 已配置爲向運行此程序的計算機發送SNMP陷阱通知。下面是一些示例結果:
{
Host=192.168.197.159,
Port=32884,
Enterprise=1.3.6.1.4.1.18334,
GenTrap=6,
SpecTrap=10,
Version=0,
PDUType=164,
TimeTicks=7792839,
ID=0,
ErrorStatus=0,
ErrorIndex=0,
Community=public,
ValueCount=5,
Value[0]=No Paper,
ValueOID[0]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[0]=4,
Value[1]=No Paper,
ValueOID[1]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[1]=4,
Value[2]=No Paper,
ValueOID[2]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[2]=4,
Value[3]=No Paper,
ValueOID[3]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[3]=4,
Value[4]=Job End,
ValueOID[4]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[4]=4,
}
{
Host=192.168.197.19,
Port=53365,
Enterprise=1.3.6.1.4.1.18334,
GenTrap=6,
SpecTrap=10,
Version=0,
PDUType=164,
TimeTicks=12469234,
ID=0,
ErrorStatus=0,
ErrorIndex=0,
Community=public,
ValueCount=6,
Value[0]=No Paper,
ValueOID[0]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[0]=4,
Value[1]=No Paper,
ValueOID[1]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[1]=4,
Value[2]=No Paper,
ValueOID[2]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[2]=4,
Value[3]=No Paper,
ValueOID[3]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[3]=4,
Value[4]=Job End,
ValueOID[4]=1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2,
ValueType[4]=4,
Value[5]=Job End,
ValueOID[5]=1.3.6.1.4.1.18334.1.1.1.2.1.83.3.1,
ValueType[5]=4,
}
1.3.6.1.4.1.18334.1.1.1.2.1.105.2.2是對的sysObjectID和C364e的1.3.6.1.4.1.18334.1.1.1.2.1.83.3.1 SysObjectID for C364。因此,似乎除了最後一個通知之外,所有通知都來自192.168.197.159下的MFP,儘管最後6個通知TIdSNMP.Trap.Host包含值192.168.197.19。
非常感謝你的解釋和解決方法/修復!有一點我仍然不太清楚:如果192.168.197.159和192.168.197.19各自在相同的100毫秒間隔內發送陷阱通知會發生什麼? TIdSNMP只是放棄第一個,或者我可以調用TIdSNMP.ReceiveTrap兩次來接收這兩條消息? – Tim
你必須爲每個單獨的陷阱調用'ReceiveTrap()'。是否放棄陷阱取決於操作系統,而不是Indy。 SNMP使用UDP。如果在從中讀取數據包之前,套接字的入站緩衝區已滿,則隨後的UDP數據包將被操作系統丟棄,直到緩衝區清除。但是,除非你在短時間內獲得大量的陷阱,否則這種睡眠時間間隔很小就不太可能發生。 –
你可以嘗試的一件事是隻要套接字在入站緩衝區中仍然有未決數據,你的循環/定時器就調用'ReceiveTrap()'在一個循環中,然後只在緩衝區已經耗盡時才休眠。 'TIdSNMP'沒有公開對'fTrapRecvBinding'成員的訪問,所以你必須公開它,然後你可以調用它的'Readable()'方法(這就是'ReceiveTrap()'調用的)。或者在一個簡短的'RecceiveTimeout'循環中調用'ReceiveTrap()',並在返回false時中斷循環。 –