Ethernet ライブラリを利用した単純な Web Server の実装
ここでは Arduino の標準の Ethernet ライブラリを利用して単純なウェブサーバーを実装します。
簡単なウェブサーバーの実装例は Example に含まれていますので、それを使えば分かるひとには分かると思います。
ここではサンプルコードをほんの少しだけ発展させて、URI をチェックして HTTP ステータスコード 200 OK を返すか、 あるいは 404 File Not Found を返すか判断してみます。
試験的にウェブサーバーがちょっと欲しいなというときに、ここで示したようなコードで動かしておけばいいと思います。
#include <Ethernet.h>
byte mac[] = { 0xDE,0xAD,0xBE,0xEF,0xF0,0x0D };
EthernetServer server(80);
void setup() {
Serial.begin(9600);
Ethernet.begin(mac);
Serial.println(Ethernet.localIP());
server.begin();
}
void loop() {
EthernetClient client = server.available();
if( client ){
Serial.println("*** New Client ***");
boolean currentLineIsBlank = true;
boolean requestLineRead = false;
char reqLine[64];
char *p = reqLine;
char *method = NULL;
char *uri = NULL;
const char delims[2] = " ";
memset( reqLine, 0, sizeof(reqLine) );
while( client.connected() ){
char c = client.read();
//Serial.write( c );
// Query
if( !requestLineRead
&& ( p - reqLine ) < (sizeof(reqLine) - 1)
&& c != '\r'
&& c != '\n' ){
*p = c;
p++;
}
if( c == '\n' && currentLineIsBlank ){
// Parse Query
p = strtok(reqLine, delims);
while( p ){
if( !method ){
method = p;
}
else if( !uri ){
uri = p;
}
p = strtok(NULL, delims);
}
// Send Response
if( !strcmp(method, "GET") && !strcmp(uri, "/pic") ){
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/plain");
client.println("Connection: close");
client.println();
client.println("OK!");
}
else{
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/plain");
client.println("Connection: close");
client.println();
client.println("File Not Found");
}
break;
}
if( c == '\n' ){
currentLineIsBlank = true;
if( !requestLineRead ){
requestLineRead = true;
}
}
else if( c != '\r' ){
currentLineIsBlank = false;
}
}
delay( 10 );
client.stop();
Serial.println("Client disconnected");
}
}
IP アドレスは DHCP から取得しています。明示的に指定するときは、Ethernet.begin で指定します。 動的に取得される IP アドレスはシリアルポートに書き出してますので、ブラウザからこのウェブサーバーに接続する時はシリアルモニタに表示された IP アドレスめがけてリクエストを送ってください。
リクエストラインだけをチェックするので、その行だけ特別にバッファ (reqLine) にコピーしてます。 クライアントからのリクエストを読み込み完了したら、バッファをチェックしてメソッドと URI を取得します。
バッファは短めにとっていて、長いリクエストラインが来たら途中まで読み込みます。(どうせ悪ふざけのリクエストでしょうから、ブチ切ってもいいでしょ)
Content-Lengh をセットしない代わりに、データ区切りとして Connection close してます。 効率は悪いですが単一クライアントが接続可能なので、1個ずつのリクエスト処理は短くする必要があるのでしかたがないです。