1

环境

操作系统:Windows 10 专业版 64 位

IDE:德尔福 XE6 + 更新 1


目标

在 Delphi XE6 中创建一个应用程序,通过 Indy 组件发送Magic 数据包,以实现本地服务器的 Wake-on-LAN。服务器已经过测试,能够从 Linux 客户端唤醒。

请注意,我想创建自己的解决方案,请没有应用建议。谢谢你。


魔术包

引用维基百科文章的一部分:

魔术包是一个广播帧,在其有效负载中包含所有 255 个字节中的 6 个字节(十六进制的 FF FF FF FF FF FF),然后是目标计算机的 48 位 MAC 地址的 16 次重复,总共 102 个字节。


基础版

我从这个页面得到了基本版本。

作者没有提及他使用的是哪个版本的 Delphi,让我们假设一个较旧的版本。

我会引用它,以防页面不可用,不变:

procedure WakeOnLan(const AMacAddress : string);
type
     TMacAddress = array [1..6] of byte;

     TWakeRecord = packed record
       Waker : TMACAddress;
       MAC   : array[0..15] of TMACAddress;
     end;

var i : integer;
    WR : TWakeRecord;
    MacAddress : TMacAddress;
    UDP : TIdUDPClient;
    sData : string;
begin
  // Convert MAC string into MAC array
  fillchar(MacAddress,SizeOf(TMacAddress),0);
  sData := trim(AMacAddress);

  if length(sData) = 17 then begin
    for i := 1 to 6 do begin
      MacAddress[i] := StrToIntDef('$' + copy(sData,1,2),0);
      sData := copy(sData,4,17);
    end;
  end;

  for i := 1 To 6 do WR.Waker[i] := $FF;
  for i := 0 to 15 do WR.MAC[i] := MacAddress;
  // Create UDP and Broadcast data structure
  UDP := TIdUDPClient.Create(nil);
  UDP.Host := '255.255.255.255';
  UDP.Port := 32767;
  UDP.BroadCastEnabled := true;
  UDP.SendBuffer(WR,SizeOf(TWakeRecord));
  UDP.BroadcastEnabled := false;
  UDP.Free;
end;

但是Delphi XE6的编译器在线抱怨:

UDP.SendBuffer(WR,SizeOf(TWakeRecord));

它说:

[dcc64 Error] main.pas(73): E2250 There is no overloaded version of 'SendBuffer' that can be called with these arguments

我的版本

重新编写了上面的代码以获得更好的可读性 + 我尝试了各种无法编译的方法,以这个结尾,它确实可以编译,尽管它显然不起作用(不会唤醒服务器)。

procedure WakeOnLan(const AMacAddress: string);

type
  TMacAddress = array [1..6] of Byte;

  TWakeRecord = packed record
    Waker : TMACAddress;
    MAC   : array [0..15] of TMacAddress;
  end;

var
  I          : Integer;
  WR         : TWakeRecord;
  MacAddress : TMacAddress;
  UDPClient  : TIdUDPClient;
  sData      : string;

begin
  FillChar(MacAddress, SizeOf(TMacAddress), 0);

  sData := Trim(AMacAddress);

  if Length(sData) = 17 then begin

    for I := 1 to 6 do begin
      MacAddress[I] := StrToIntDef('$' + Copy(sData, 1, 2), 0);
      sData := Copy(sData, 4, 17);
    end;

  end;

  for I := 1 to 6  do WR.Waker[I] := $FF;
  for I := 0 to 15 do WR.MAC[I]   := MacAddress;

  UDPClient := TIdUDPClient.Create(nil);
  try

//    UDP.Host := '255.255.255.255';
//    UDP.Port := 32767;

    UDPClient.BroadCastEnabled := True;
    UDPClient.Broadcast(RawToBytes(WR, SizeOf(TWakeRecord)), 7);

//    UDP.SendBuffer(RawToBytes(WR, SizeOf(TWakeRecord)));

  UDPClient.BroadcastEnabled := False;
  finally
    UDPClient.Free;
  end;
end;

编辑1

我根本不想使用任何 IP 地址,只需要纯 MAC 地址即可。

4

2 回答 2

2

原始代码是为 Indy 9 编写的。Indy 10 等价物看起来更像这样:

UDPClient := TIdUDPClient.Create(nil);
try
  UDP.Host := '255.255.255.255';
  UDP.Port := 32767;
  UDP.IPVersion := Id_IPv4;
  UDP.BroadcastEnabled := True;
  UDP.SendBuffer(RawToBytes(WR, SizeOf(WR)));
finally
  UDP.Free;
end;

或者:

UDPClient := TIdUDPClient.Create(nil);
try
  UDP.IPVersion := Id_IPv4;
  UDP.BroadCastEnabled := True;
  UDP.SendBuffer('255.255.255.255', 32767, RawToBytes(WR, SizeOf(WR)));
finally
  UDP.Free;
end;

或者:

UDP := TIdUDPClient.Create(nil);
try
  UDP.IPVersion := Id_IPv4;
  UDP.Broadcast(RawToBytes(WR, SizeOf(WR)), 32767);
finally
  UDP.Free;
end;
于 2018-08-02T21:10:23.880 回答
0

这段代码对我有用,看一下 SendBuffer 函数的参数(服务器、端口、缓冲区):

UDP.IPVersion := Id_IPv4;
UDP.BroadCastEnabled := True;
UDP.SendBuffer('192.168.1.255', 9, RawToBytes(WR, SizeOf(WR)));
UDP.BroadCastEnabled := False;

请注意,广播地址“255.255.255.255”可能不起作用,您应该以限制广播的范围为例。

于 2018-08-02T16:25:59.023 回答