2010-12-29 13 views
8

Tôi đang sử dụng Delphi và tôi muốn xác định địa chỉ MAC vật lý của thiết bị mạng trong mạng của mình, trong trường hợp này là bản thân Router.Delphi: Nhận MAC của Router

Mã của tôi:

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; 

nơi 10.0.0.1 là router của tôi.

Than ôi, QuickSend luôn gửi "Kết nối được đặt lại bởi peer # 10054". Tôi đã cố gắng sửa đổi MIB-OID và tôi cũng đã thử IP 127.0.0.1 mà kết nối sẽ không bao giờ thất bại. Tôi không tìm thấy bất kỳ Hướng dẫn có thể sử dụng nào về TIdSNMP tại Google. :-(

Trân Daniel Marschall

+0

Indy quá crappy, 10054 là TCP liên quan. Trong khi đó, bạn đã có bản ghi ARP cho 10.0.0.1, hãy sử dụng API trình trợ giúp IP để thẩm vấn. –

+0

Indy không phải là quá crappy thực sự, bạn phải xử lý ngoại lệ ... thử ... ngoại trừ bất cứ ai ?! một điều khác mà tôi vừa mới phát hiện ra là ngay cả tho 'bạn xử lý ngoại lệ, đôi khi ngoại lệ # 10054 vẫn được nâng lên NẾU bạn đã cài đặt nhật ký eureka, bạn có thể giải quyết vấn đề này bằng cách thêm LỌC EXCEPTION cho lỗi EIdSocket hoặc thứ gì đó tương tự ... không có ngoại lệ, mọi thứ hoạt động hoàn hảo !! – ComputerSaysNo

+1

@Dorin Duminica: 10054 có nghĩa là máy chủ lưu trữ đại lý nào đã được thử lại với TCP RST hoặc ICMP UNREACH. Dù sao, Indy được sử dụng để sử dụng ngoại lệ cho kiểm soát dòng chảy, đó là lý do tại sao một số lỗi vô nghĩa bong bóng cho độ sâu của Indy thời gian để thời gian. –

Trả lời

14

Bạn có thể sử dụng chức năng SendARP để có được địa chỉ Mac.

kiểm tra mẫu này

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 Thành thật mà nói, tôi chưa bao giờ nghe nói về DLL đó trước đây! –

+0

Cảm ơn bạn rất nhiều! Bạn đã giúp tôi rất nhiều với mã đó. :-) Tôi đã bắt đầu đọc IP Helper Reference từ MSDN, nhưng tôi không biết rằng SendARP() thực hiện công việc. –

+0

+1 RRUZ đang chơi rất nhiều thứ trên internet từ những gì tôi đã thấy trên blog của anh ấy :-) công việc tốt !! – ComputerSaysNo

5

Không có nhu cầu ăn cắp sấm sét của RRUZ, Tôi cung cấp các biến thể sau đây, lấy từ codebase của tôi, với một số quan sát Tôi đã làm điều này như là một câu trả lời chứ không phải là một bình luận để bao gồm mã số

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; 

Có một vài điểm cần thực hiện.

Không cần phải gọi WSAStartup/WSACleanup.

EDIT Vì RRUZ chỉ ra trong nhận xét, tài liệu winsock không được miễn inet_addr từ WSAStartup/WSACleanup nên tôi rút lại điểm này. Trên Vista nó đơn giản hơn chỉ để gọi RtlIpv4StringToAddress. Có nói tất cả điều đó, inet_addr là dễ dàng như vậy để thực hiện nó chỉ có thể được dễ dàng hơn để cuộn của riêng bạn.

Thứ hai, việc khai báo inet_addr trong WinSock.pas là không chính xác. Nó khai báo giá trị trả về là một kiểu u_long được định nghĩa trong WinSock.pas là Longint. Đây là một số nguyên 4 byte đã ký nhưng nó phải là một số nguyên 4 byte không dấu, ULONG. Nếu không có diễn viên rõ ràng, bạn có thể gặp lỗi phạm vi.

+0

+1 cho cả bạn và RRUZ. –

+0

@David ở đâu khai báo lớp ngoại lệ 'EMacAddressError'? – RRUZ

+0

@RRUZ EMacAddressError = class (Ngoại lệ); (hoặc bất cứ điều gì bạn muốn) –