2010-12-29 2 views
8

Я использую Delphi, и я хочу определить физический MAC-адрес сетевого устройства в моей сети, в этом случае сам маршрутизатор.Delphi: получить MAC-адрес маршрутизатора

Мой код:

var 
    idsnmp: tidsnmp; 
    val:string; 
begin 
    idsnmp := tidsnmp.create; 
    try 
    idsnmp.QuickSend('.1.3.6.1.2.1.4.22.1.2', 'public', '10.0.0.1', val); 
    showmessage(val); 
    finally 
    idsnmp.free; 
    end; 
end; 

где 10.0.0.1 является маршрутизатор.

Увы, QuickSend всегда отправляет «Сброс соединения с помощью однорангового узла 10054». Я попытался изменить MIB-OID, и я также попробовал IP 127.0.0.1, которое никогда не должно прерываться. Я не нашел в Google полезных руководств по TIdSNMP. :-(

С уважением Daniel Marschall

+0

Indy настолько дрянной, 10054 связан TCP. Между тем, у вас уже есть запись ARP для 10.0.0.1, используйте IP Helper API для опроса. –

+0

Indy не так дерьмоват на самом деле, вам приходится обрабатывать исключения ... попробуйте ... кроме кого-нибудь ?! еще одна вещь, которую я недавно обнаружил, заключается в том, что даже если вы обрабатываете исключения, иногда исключение # 10054 все еще возникает, если у вас установлен журнал eureka, вы можете решить эту проблему, добавив EXCEPTION FILTER для ошибки EIdSocket или что-то в этом роде ... нет никаких исключений, все работает отлично !! – ComputerSaysNo

+1

@ Dorin Duminica: 10054 означает, что агент-агент вызывается либо TCP RST, либо ICMP UNREACH. Во всяком случае, Indy использовал исключения для управления потоком, поэтому некоторые бессмысленные ошибки пузырьков для глубин Indy время от времени. –

ответ

14

Вы можете использовать функцию SendARP, чтобы получить MAC-адрес.

проверить этот образец

uses 
Windows, 
WinSock, 
SysUtils; 


function SendArp(DestIP,SrcIP:ULONG;pMacAddr:pointer;PhyAddrLen:pointer) : DWord; StdCall; external 'iphlpapi.dll' name 'SendARP'; 


function GetMacAddr(const IPAddress: string; var ErrCode : DWORD): string; 
var 
MacAddr : Array[0..5] of Byte; 
DestIP  : ULONG; 
PhyAddrLen : ULONG; 
WSAData : TWSAData; 
begin 
    Result :=''; 
    WSAStartup($0101, WSAData); 
    try 
    ZeroMemory(@MacAddr,SizeOf(MacAddr)); 
    DestIP :=inet_addr(PAnsiChar(IPAddress)); 
    PhyAddrLen:=SizeOf(MacAddr); 
    ErrCode :=SendArp(DestIP,0,@MacAddr,@PhyAddrLen); 
    if ErrCode = S_OK then 
    Result:=Format('%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x',[MacAddr[0], MacAddr[1],MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]]) 
    finally 
    WSACleanup; 
    end; 
end; 
+1

+1 Честно говоря, я никогда не слышал об этой DLL раньше! –

+0

Спасибо вам большое! Ты очень помог мне с этим кодом. :-) Я уже начал читать ссылку IP Helper Reference из MSDN, но я не знал, что SendARP() выполняет эту работу. –

+0

+1 RRUZ много играет с интернет-вещами из того, что я видел на его блоге :-) хорошая работа !! – ComputerSaysNo

5

Не желая украсть гром RRUZ, Я предлагаю следующий вариант, взятый из моей кодовой базы, с некоторыми наблюдениями. Я сделал это скорее как ответ, чем комментарий, чтобы включить код.

type 
    TMacAddress = array [0..5] of Byte; 

function inet_addr(const IPAddress: string): ULONG; 
begin 
    Result := ULONG(WinSock.inet_addr(PAnsiChar(AnsiString(IPAddress)))); 
end; 

function SendARP(DestIP, SrcIP: ULONG; pMacAddr: Pointer; var PhyAddrLen: ULONG): DWORD; stdcall; external 'Iphlpapi.dll'; 

function GetMacAddress(const IPAddress: string): TMacAddress; 
var 
    MaxMacAddrLen: ULONG; 
begin 
    MaxMacAddrLen := SizeOf(Result); 
    if SendARP(inet_addr(IPAddress), 0, @Result, MaxMacAddrLen)<>NO_ERROR then begin 
    raise EMacAddressError.CreateFmt('Unable to do SendARP on address: ''%s''', [IPAddress]); 
    end; 
end; 

Существует несколько моментов.

Нет необходимости звонить WSAStartup/WSACleanup.

EDIT Как RRUZ указывает на комментарий, документация Winsock не освобождается Явно inet_addr от WSAStartup/WSACleanup поэтому я втягивать эту точку. В Vista проще просто вызвать RtlIpv4StringToAddress. Сказав все это, inet_addr настолько прост в реализации, что может быть проще свернуть самостоятельно.

Во-вторых, неверно объявление объявления inet_addr в WinSock.pas. Он объявляет возвращаемое значение типа u_long, которое определено в WinSock.pas как Longint. Это подписанное 4-байтовое целое число, но оно должно быть беззнаковым 4-байтовым целым, ULONG. Без явного броска вы можете получить ошибки диапазона.

+0

+1 для вас и RRUZ. –

+0

@David где объявление класса исключения EMacAddressError? – RRUZ

+0

@RRUZ EMacAddressError = класс (исключение); (или что бы вы ни хотели) –

Смежные вопросы