Wake On LANを試してみようと以下の記事を書いたわけだが、PowerShellでマジックパケットを送信しようとしたところ、PowerShellのセキュリティや文字コードがややこしいと感じて、自分でプログラム書いたほうがはやいってことになりアプローチした。
会社のPCを電源付けっぱなしはよろしくないんじゃねと思ってWake On LANを試してみた
プログラムに興味ない人は、以下のzip(解凍結果はexe)ダウンロードして使ってみるべし。
SendMagicPacket
コマンドプロンプトで動作するプログラムで.Net Framework 4.6.1が入ってれば動く。Windows 10であれば問題ないでしょ。
コマンド仕様は以下の通り。
●パラメータ1:ポート番号
普通は7か9ということだが、ネットワークによっては閉じられていることもあるかと思って指定できるようにした。9と指定していおけば大丈夫だと思う。
●パラメータ2:ブロードキャストアドレス
ネットワーク内のどの範囲にパケットを送るかの指定で、ディレクテッドブロードキャストアドレスのみが利用できて、255.255.255.255のようなリミテッドブロードキャストアドレスはダメらしい。例えば起動したいIPアドレスが192.168.0.100だとしたら、192.168.0.255としておけばよいはず。
●パラメータ3:MACアドレス
起動したいマシンのMACアドレスで、16進数2桁をハイフンでつなげた文字。例:01-23-45-67-89-0A
●解説
マジックパケットなる一定のルールに基づいたメッセージを、UDPプロトコルでネットワークに送っている。
以下、C#(Visual Studio 2007)のソースコード。コンソールアプリケーションをちゃんと作ったのははじめてかも。パラメータチェック、UDPクライアントのメッセージ送信時の例外処理までやっているのでけっこう使えるものに仕上がったんじゃないか。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace SendMagicPacket
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 3)
{
Console.Write("パラメータは3つ(1.ポート番号 2.ブロードキャストアドレス 3.MACアドレス");
return;
}
string p1 = args[0];
int port = -1;
if (!int.TryParse(p1, out port) && !(0 <= port && port <= 65535))
{
Console.Write("パラメータ1(ポート番号)が0~65535でない");
return;
}
string p2 = args[1];
IPAddress ipaddr;
if (!IPAddress.TryParse(p2, out ipaddr))
{
Console.Write("パラメータ2がIPアドレスではない");
return;
}
string p3 = args[2];
string[] mac = p3.Split('-');
if (mac.Length != 6)
{
Console.Write("パラメータ3がMACアドレスではない(ハイフンで区切られた6つのセクション)");
return;
}
byte[] macaddr = { 0, 0, 0, 0, 0, 0 };
for (int i = 0; i < 6; i++)
{
byte result = 0;
try
{
result = Convert.ToByte(mac[i], 16);
}
catch (FormatException)
{
Console.Write("パラメータ3がMACアドレスではない(各セクションに0~9,a~fの文字以外が使われている)");
return;
}
catch (OverflowException)
{
Console.Write("パラメータ3がMACアドレスではない(各セクション桁あふれしている)");
return;
}
macaddr[i] = result;
}
if (MagicPacket.Send(port, ipaddr, macaddr) == true)
Console.Write("成功:ポート番号" + p1 + " ブロードキャストアドレス" + p2 + " MACアドレス" + p3);
}
}
static class MagicPacket
{
static public bool Send(int port, IPAddress broad, byte[] macAddress)
{
try
{
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
for (int i = 0; i < 6; i++)
writer.Write((byte)0xff);
for (int i = 0; i < 16; i++)
writer.Write(macAddress);
UdpClient client = new UdpClient();
client.EnableBroadcast = true;
client.Send(stream.ToArray(), (int)stream.Position, new IPEndPoint(broad, port));
}
catch (ArgumentNullException e)
{
Console.Write("ArgumentNullException: {0}", e);
return false;
}
catch (SocketException e)
{
Console.Write("SocketException: {0}", e);
return false;
}
return true;
}
}
}
ちょっとおまけだけど、上記のclient.Sendをやった後に、client.Close()とやってはいけない。
明示的にCloseしておけばメモリーが解放されていいかと思ったが、このせいでSendが動かなかった。
ということに気付くのに数時間を要してしまった。。