请解释一下这个 LAN 唤醒脚本的工作原理

发布于 2024-10-19 17:42:13 字数 1596 浏览 2 评论 0原文

几个月前,我在博客上发现了这段 PowerShell 代码。它无需使用外部程序即可将 LAN 唤醒信号发送到您选择的 MAC 地址。我对这篇博文发表了评论,并要求作者描述一下脚本背后的逻辑,因为我对此感到好奇。稍后我又回到博客文章,看看作者是否回复了我的评论。我很惊讶地发现我被重定向到一个页面,作者说他由于崩溃而丢失了他的博客。我不记得它的细节,但我想我不再为那个博客添加书签了。

所以现在我想请求 Stack Overflow 上的聪明人看看这段代码并向我解释它的逻辑。每行都有评论就太好了。我很好奇这是如何运作的。它似乎比我发现的其他脚本更强大,因为它可以跨子网工作。不过我对网络了解不多。

我最好奇的事情之一是最后的 for 循环。为什么要多次发送信号?为什么在不同的端口上?但我真的很想知道整个脚本背后的逻辑。

代码:

param (
    $targetMac,
    $network = [net.ipaddress]::Broadcast,
    $subnet = [net.ipaddress]::Broadcast
)
try {
    if($network.gettype().equals([string])) {
        $network = [net.ipaddress]::Parse($network);
    }
    if($subnet.gettype().equals([string])) {
        $subnet = [net.ipaddress]::Parse($subnet);
    }
    $broadcast = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $subnet.address -bor $network.address))

    $mac = [Net.NetworkInformation.PhysicalAddress]::Parse($targetMac.toupper().replace(".",""))

    $u = New-Object net.sockets.udpclient
    $ep = New-Object net.ipendpoint $broadcast, 0
    $ep2 = New-Object net.ipendpoint $broadcast, 7
    $ep3 = New-Object net.ipendpoint $broadcast, 9

    $payload = [byte[]]@(255,255,255, 255,255,255);
    $payload += ($mac.GetAddressBytes()*16)

    for($i = 0; $i -lt 10; $i++) {
        $u.Send($payload, $payload.Length, $ep) | Out-Null
        $u.Send($payload, $payload.Length, $ep2) | Out-Null
        $u.Send($payload, $payload.Length, $ep3) | Out-Null
        sleep 1;
    }
} catch {
    $Error | Write-Error;
}

I found this PowerShell code on a blog a couple months ago. It sends wake-on-LAN signals to the MAC address of your choice without using external programs. I commented on the blog post and asked the author to describe the logic behind the script because I was curious about it. I went back to the blog post at a later date to see if the author replied to my comment. I was surprised to see that I was redirected to a page where the author said he lost his blog due to a crash. I can't remember the details of it, but I don't think I have that blog bookmarked anymore.

So now I would like to request to have the brilliant minds at Stack Overflow look at this code and explain its logic to me. A comment for each line would be fantastic. I'm quite curious to know how this works. It appears to be more robust than other scripts that I've found in that it works across subnets. I don't know much about networking, though.

One of the things I'm most curious about is the for loop at the end. Why send the signal multiple times? And why on different ports? But I really would like to know the logic behind the entire script.

The code:

param (
    $targetMac,
    $network = [net.ipaddress]::Broadcast,
    $subnet = [net.ipaddress]::Broadcast
)
try {
    if($network.gettype().equals([string])) {
        $network = [net.ipaddress]::Parse($network);
    }
    if($subnet.gettype().equals([string])) {
        $subnet = [net.ipaddress]::Parse($subnet);
    }
    $broadcast = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $subnet.address -bor $network.address))

    $mac = [Net.NetworkInformation.PhysicalAddress]::Parse($targetMac.toupper().replace(".",""))

    $u = New-Object net.sockets.udpclient
    $ep = New-Object net.ipendpoint $broadcast, 0
    $ep2 = New-Object net.ipendpoint $broadcast, 7
    $ep3 = New-Object net.ipendpoint $broadcast, 9

    $payload = [byte[]]@(255,255,255, 255,255,255);
    $payload += ($mac.GetAddressBytes()*16)

    for($i = 0; $i -lt 10; $i++) {
        $u.Send($payload, $payload.Length, $ep) | Out-Null
        $u.Send($payload, $payload.Length, $ep2) | Out-Null
        $u.Send($payload, $payload.Length, $ep3) | Out-Null
        sleep 1;
    }
} catch {
    $Error | Write-Error;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不必你懂 2024-10-26 17:42:13
#These are the parameters to the script. The only mandatory param here is the mac address
#[net.ipaddress]::Broadcast will resolve to something like 255.255.255.255
param (
    $targetMac,
    $network = [net.ipaddress]::Broadcast,
    $subnet = [net.ipaddress]::Broadcast
)

#We start the try, catch error handling here.
#if something in try block fails, the catch block will write the error
try {

#This will evaludate to False. Hence, $network will have whatever was passed through params or the default value
#in this case the default value is 255.255.255.255
    if($network.gettype().equals([string])) {
        $network = [net.ipaddress]::Parse($network);
    }

#This will evaludate to False. Hence, $network will have whatever was passed through params or the default value
#in this case the default value is 255.255.255.255    
    if($subnet.gettype().equals([string])) {
        $subnet = [net.ipaddress]::Parse($subnet);
    }

    #Not sure if this is really required here. But, assuming that the default value for both $network and $subet is 255.255.255.255,
    #this will result in $broadcast set to 255.255.255.255
    $broadcast = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $subnet.address -bor $network.address))

#This again assumes that you had given . as the delimeter in MAC address and removes that from MAC address    
    $mac = [Net.NetworkInformation.PhysicalAddress]::Parse($targetMac.toupper().replace(".",""))

#Create a new object of type net.sockets.udpclient
    $u = New-Object net.sockets.udpclient

#WOL magic packet can be sent on port 0, 7, or 9    
#Create a end point for the broadcast address at port 0    
    $ep = New-Object net.ipendpoint $broadcast, 0

#Create a end point for the broadcast address at port 7    
    $ep2 = New-Object net.ipendpoint $broadcast, 7

#Create a end point for the broadcast address at port 9    
    $ep3 = New-Object net.ipendpoint $broadcast, 9

#Create a payload packet
#First, create a byte array
    $payload = [byte[]]@(255,255,255, 255,255,255);

#add the mac address to the above byte array    
    $payload += ($mac.GetAddressBytes()*16)

#Send 10 magic packets for each port number or end point created above.
#one is more than enough. If everything is congfigured properly
    for($i = 0; $i -lt 10; $i++) {
        $u.Send($payload, $payload.Length, $ep) | Out-Null
        $u.Send($payload, $payload.Length, $ep2) | Out-Null
        $u.Send($payload, $payload.Length, $ep3) | Out-Null
        sleep 1;
    }
} catch {
#catch block catches any error from try block
    $Error | Write-Error;
}
#These are the parameters to the script. The only mandatory param here is the mac address
#[net.ipaddress]::Broadcast will resolve to something like 255.255.255.255
param (
    $targetMac,
    $network = [net.ipaddress]::Broadcast,
    $subnet = [net.ipaddress]::Broadcast
)

#We start the try, catch error handling here.
#if something in try block fails, the catch block will write the error
try {

#This will evaludate to False. Hence, $network will have whatever was passed through params or the default value
#in this case the default value is 255.255.255.255
    if($network.gettype().equals([string])) {
        $network = [net.ipaddress]::Parse($network);
    }

#This will evaludate to False. Hence, $network will have whatever was passed through params or the default value
#in this case the default value is 255.255.255.255    
    if($subnet.gettype().equals([string])) {
        $subnet = [net.ipaddress]::Parse($subnet);
    }

    #Not sure if this is really required here. But, assuming that the default value for both $network and $subet is 255.255.255.255,
    #this will result in $broadcast set to 255.255.255.255
    $broadcast = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $subnet.address -bor $network.address))

#This again assumes that you had given . as the delimeter in MAC address and removes that from MAC address    
    $mac = [Net.NetworkInformation.PhysicalAddress]::Parse($targetMac.toupper().replace(".",""))

#Create a new object of type net.sockets.udpclient
    $u = New-Object net.sockets.udpclient

#WOL magic packet can be sent on port 0, 7, or 9    
#Create a end point for the broadcast address at port 0    
    $ep = New-Object net.ipendpoint $broadcast, 0

#Create a end point for the broadcast address at port 7    
    $ep2 = New-Object net.ipendpoint $broadcast, 7

#Create a end point for the broadcast address at port 9    
    $ep3 = New-Object net.ipendpoint $broadcast, 9

#Create a payload packet
#First, create a byte array
    $payload = [byte[]]@(255,255,255, 255,255,255);

#add the mac address to the above byte array    
    $payload += ($mac.GetAddressBytes()*16)

#Send 10 magic packets for each port number or end point created above.
#one is more than enough. If everything is congfigured properly
    for($i = 0; $i -lt 10; $i++) {
        $u.Send($payload, $payload.Length, $ep) | Out-Null
        $u.Send($payload, $payload.Length, $ep2) | Out-Null
        $u.Send($payload, $payload.Length, $ep3) | Out-Null
        sleep 1;
    }
} catch {
#catch block catches any error from try block
    $Error | Write-Error;
}
糖粟与秋泊 2024-10-26 17:42:13

维基百科对 LAN 唤醒有很好的解释:

http://en.wikipedia.org /wiki/Wake-on-LAN

摘自该文章:

[The Magic Packet] is typically sent as a UDP datagram to port 7 or 9, but actually it can be 
sent on any port.

猜测多次发送数据包的原因是为了解决偶尔的网络冲突。如果发生冲突,则必须重新发送数据包。

Wikipedia has a good explanation of Wake-On-Lan:

http://en.wikipedia.org/wiki/Wake-on-LAN

Excerpt from that article:

[The Magic Packet] is typically sent as a UDP datagram to port 7 or 9, but actually it can be 
sent on any port.

My guess as to the reason for sending the packet multiple times is to account for the occasional network collision. If a collision occurs, then the packet must be re-sent.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文