2012/08/27(Mon)Wake On Lan In C#

はてブ数 2012/08/27 23:59 プログラミング::C# つーさ

ある日のTwitterにて。

気まぐれにdevenvしておよそ10分後にできたものがこれだっ

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace WoL
{
  class Program
  {
    static void Main(string[] args)
    {
      // args[0] = "DE-AD-BE-EF-11-FE"
      new Action<string>(a=>new UdpClient(0).Send(Array.ConvertAll(("FF-FF-FF-FF-FF-FF-"+string.Join("-",new string[]{a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a})).Split('-'), s=>byte.Parse(s, NumberStyles.AllowHexSpecifier)),102,new IPEndPoint(0xFFFFFFFF, 9)))(args[0]);
    }
  }
}

設定など要らんっ

自分のマシンに対して使って動くことは確認した。
ほんとは140文字以内にしてツイートしたかった。

追記

解説した。

それを踏まえて上のコードを分解。

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace WoL
{
  class Program
  {
    static void Main(string[] args)
    {
      // args[0] = "DE-AD-BE-EF-11-FE" みたいな形式で入ってることを期待。
      // 毎回 args[0]って書くのはしんどい
      string a = args[0];

      // 間に-を挟みつつ、アドレス文字列を16回繰り返す。頭にFFを6個つける。
      string packet = "FF-FF-FF-FF-FF-FF-" + string.Join("-", new string[]{a,a,a,a,  a,a,a,a,  a,a,a,a,  a,a,a,a, });

      // '-' で分割してそれぞれ byteとしてParse。Array.ConvertAllはできる子。
      byte[] packetData = Array.ConvertAll(packet.Split('-'), s => byte.Parse(s, NumberStyles.AllowHexSpecifier));

      // Local側は port0 = Ephemeralポートを開く。送信すべきデータは102バイトになってるはず。
      // 送り先は0xFFFFFFFF=255.255.255.255 = Limited Broadcast Address、ポートは任意だけどUDP well-knownのdiscardでも使っとくか。
      new UdpClient(0).Send(packetData, 102, new IPEndPoint(0xFFFFFFFF, 9));

      // ソケットを閉じるなんてめんどくさいことをするはずがないだろう!
      // new UdpClient(0).Send(packetData, 102, "255.255.255.255", 9); のが短かった!
    }
  }
}

どう書く?.org とかが残ってたらお題として面白いのになぁ。というかありそう。

入力が16進でなけりゃ、Array.ConvertAll の第二引数をラムダにするまでもなく、
Array.ConvertAll(packet.Split('-'), byte.Parse) とかって書けたりする。えらい。

byte[] packetDataの生成はLinqだと、こう?

  byte[] packetData = packet.Split('-').Select(s => byte.Parse(s, NumberStyles.AllowHexSpecifier)).ToArray();

MACアドレスの例は思いつきで書いたけど、DEAD BEEF LIFE ってどんな人生だろう。

16進文字列を小文字に限定したら
s=>byte.Parse(s,NumberStyles.AllowHexSpecifier) の代わりに
s=>(byte)(s[0]%87%48*16+s[1]%87%48)
って書ける。