201404132349UDP函式庫喚醒電腦(Wake On Lan)

網路模組傳輸資料的話,會使用到2種通訊協定

  • TCP (Transmission Control Protocol):連接導向的、可靠的、基於位元組流的傳輸層通訊協定
  • UDP (User Datagram Protocol):簡單的面向數據報的傳輸層協議,為不可靠傳遞

為確保網路連線的可靠性、強壯性、流量控制,大多使用TCP協定

任何事都是一體兩面,可靠穩定安全的通訊協定,往往需要繁瑣的流程且耗量時間

然而另一種通訊協定UDP,手續簡單、動作快速,往往很快地可以接近即時的需求

但它缺乏可靠性且屬於非連接導向協定,有一定量的丟包、出錯和複製貼上

 

arduino提供的Standard Libraries中有關於Ethernet的函式庫,見連接 Ethernet Library

可看到Ethernet、IPAddress、Server、Client和EthernetUDP五個class

之所以把UDP獨立建立出來成為一個class,就如上面所述的

而我在使用arduino的應用中,有趣的是,很多時候我都捨棄TCP改使用UDP

一來是因為arduino都被我拿來當做"衛星",是每個小區域內網的控制中心

二來是希望arduino發出指令的速度要夠快,能讓人有real time的感覺

接下來我就用"Wake On Lan"(網路喚醒)的例子來說明

 

幻想一下,今天在成人藝術展覽會中,有3個展區,每個展區都有5台電腦

可是我們去看展覽時都不會看到電腦和訊號線,因為都被完美地藏在展板或其它地方

有些放置電腦的地方可能非常擠!每次開機都是一種痛苦!而且有15台耶!(這是真的...我親身被折磨過....)

倘若我們3組arduino+ethernet,每組再加上一個簡單的定時裝置

每天早上10點arduino就用wake on lan的方式開啟電腦;電腦本身設定每天5點半時自動關機

藉由這樣子解決了每日電腦的固定開/關機動作!

 

UDP的範例說明,可以見arduino的官網 Sending and Receiving String via UDP

在這裡說明一下如何藉由UDP做出wake on lan的動作

首先,要先確認主機板有支援wake on lan的功能,可進BIOS觀看

某些router機器也需要做設定,一般switch和hub到是沒有什麼問題

wake on lan接收的是一種稱為"魔法封包(Magic Packet)"的廣播性的訊框(frame)

封包長度共由102個bytes組成,結構如下:

FF FF FF FF FF FF  → 前6個固定為FF
XX XX XX XX XX XX → 目標電腦的MAC位址,重複第1次
XX XX XX XX XX XX → 目標電腦的MAC位址,重複第2次
.........
XX XX XX XX XX XX → 目標電腦的MAC位址,重複第16次

開頭由6個數值0xFF的bytes組成,之後輸入目標電腦網卡的MAC位址,要重複16次

算出來封包byte數為 6 + (6 x 16) = 102

魔法封包是以廣播(broadcast)的方式在傳送,可對區網或特定子網路,port多為7或9

可以先上網下載免費的wake on lan軟體測試看看port是多少

因為我測試的電腦port = 7,所以下面程式範例使用port 7,且只針對一台電腦做範例

考量到可能會控制到很多台電腦,因為UDP object是使用local型態

也就是結束了這個function就會被release,畢竟arduino的網路連線有數量限制


#include "SPI.h"
#include "Ethernet.h"
#include "EtherUdp.h"

/* Enter a MAC address for your controller below.
   begin() function of Ethernet.h:
   void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); */
byte MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress IP(192, 168, 1, 100);
IPAddress Subnet(255, 255, 255, 0);
IPAddress Gateway(192, 168, 1, 1);
IPAddress DNS(8, 8, 8, 8);

/* WOL Configuration */
byte PC_MAC[] = {0x1C, 0x6F, 0x65, 0xC7, 0xFB, 0xC9};
IPAddress BROAD_CAST(192, 168, 1, 255);

/* Serial port receive buffer */
#define BUFFER_SIZE 16
char inBuffer[BUFFER_SIZE];

void setup()
{
  /* For voltage stable*/
  delay(300);

  Ethernet.begin(MAC, IP, DNS, Gateway, Subnet);
  
  Serial.begin(9600);
}

void loop()
{ 
  while (Serial.available() > 0)
  {
    Serial.readBytes(inBuffer, BUFFER_SIZE);
    if (inBuffer[0] == '1')
      WakeOnLan();
  }
}

void WakeOnLan()
{
  int i, j, mac_idx, pkt_idx = 0;
  byte SendWOL[102];
  EthernetUDP WOL_UDP;
  int WOL_PORT = 7;  /* UDP port of wake on lan is 7 or 9 */
  
  /* Magic Packet Header - 6 bytes (0xFF) */
  for (i=0; i<6; i++, pkt_idx++)
    SendWOL[pkt_idx] = 0xFF;
  /* Magic Packet Mac Address - 16 times MAC address (96 bytes) */
  for (i=0; i<16; i++)
  {
    for (mac_idx=0; mac_idx<6; mac_idx++, pkt_idx++)
      SendWOL[pkt_idx] = PC_MAC[mac_idx];
  }
  
  /* Show magic packet */
  j = 0;
  Serial.println("Magic Packet (Wake on Lan) : ");
  for (i=0; i<102; i++)
  {
    Serial.print(SendWOL[i], HEX);
    if (j < 5)
    {
      Serial.print(" ");
      j++;
    }
    else
    {
      Serial.println();
      j = 0;
    }
  }
  
  /* Send magic packet */
  WOL_UDP.begin(7);
  WOL_UDP.beginPacket(BROAD_CAST, 7);
  WOL_UDP.write(SendWOL, sizeof(SendWOL));
  WOL_UDP.endPacket();
  WOL_UDP.stop();
}

 

 

 

沒有上一則|日誌首頁|沒有下一則
回應
關鍵字
    沒有新回應!