CAD日記

主にAutoCADのことについて書いているけど、近頃は投資系ネタに注力している。自動売買、仮想通貨、PC関係、プログラミングなど。@caddiary

ソフト開発

インフラSEへの道~マジックパケットを送信してマシンを起動する~

投稿日:2020年7月5日 更新日:

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が動かなかった。
ということに気付くのに数時間を要してしまった。。

-ソフト開発

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

no image

環境変数TEMPトラブルについて振り返る

プログラムから環境変数TEMPで指定されたフォルダにファイルが作れないことがわかった時点で、この問題は解決したも同じだった。TEMPの値を「%USERPROFILE%\AppData\Local\Te …

no image

円周率

3.1415926535…。私が記憶しているのはここまでです。スーパーコンピュータを使って数億桁まで計算、なんてニュースをよく聞きますね。コンピュータの性能向上とアルゴリズムの工夫に対する …

no image

レイヤ付きPDFを出力する弊害

Illustratorという高価なアプリを使ってPDFを出力すると、PDFにレイヤが付いてしまって非表示にしたはずのレイヤが表示されて困ったなという事象に2回遭遇したので以下に記録。共通しているのが、 …

PDFファイルを扱うプログラミング用ライブラリ一覧

以下の記事がよく読まれているみたいなので、もっと幅広く「PDFファイルを扱うプログラミング用ライブラリ一覧」という本記事を書いてみる気になった。 iTextSharpのバージョンとライセンスが難しい …

no image

マルチスレッド

ついに出来ました。 マルチスレッド技術を利用した画期的機能が。 って、そんな大したものではありません。 スレッド化技術は、この時代当たり前になりつつありますが、 なかなか難しそうで、手をつけてませんで …