uIPのイベント
uIPで簡単なHTTPクライアントを書いてみる。
大げさなものではなくGETしてそれを画面に出力するだけ。
まずはuIPのドキュメント通りに、各状態に合わせたハンドラを呼んでやる
void NetServer::DoEvent() { if (uip_aborted()) { AbortedHandler(); } if (uip_timedout()) { TimeoutHandler(); } if (uip_closed()) { ClosedHandler(); } if (uip_connected()) { ConnectedHandler(); } if (uip_acked()) { AckedHandler(); } if (uip_newdata()) { NewDataHandler(); } if (uip_rexmit() || uip_newdata() || uip_acked() || uip_acked() || uip_connected() || uip_poll()) { SendDataHandler(); }
次にそれぞれのハンドラを定義してやります。
今回は実験なので、効率とか誰がメモリ解放するのかとか、エラーのときは?とかは一切考えていません。
void NetServer::ConnectedHandler() { printf("%s\n", __FUNCTION__); struct server_state* s = (struct server_state *)uip_conn->appstate; const char* message = "GET /file HTTP/1.0\r\nServer:192.168.100.2\r\n\r\n"; s->message = new char[strlen(message) + 1]; strcpy(s->message, message); s->length = strlen(message) + 1; } void NetServer::AckedHandler() { printf("%s\n", __FUNCTION__); struct server_state* s = (struct server_state *)uip_conn->appstate; s->length -= uip_conn->len; s->message += uip_conn->len; if(s->length == 0) { printf("send done\n"); } } void NetServer::NewDataHandler() { printf("%s\n", __FUNCTION__); for (dword i = 0; i < GetDataLength(); i++) { printf("%c", (char)uip_appdata[i]); } } void NetServer::SendDataHandler() { printf("%s\n", __FUNCTION__); struct server_state* s = (struct server_state *)uip_conn->appstate; if (s->length != 0) { uip_send((volatile u8_t*)s->message, s->length); } }
フローとしては
1. 接続が完了すると ConnectedHandlerが呼ばれる
2. GETを発行するために、GET文字列と長さを格納
3. 送信
4. ackedが返ってきてまだ未送信分がある場合や、再送の必要があれば再送信します。
5.uip_newdata()が1だったらデータが返ってきています。
これを踏まえたうえで次のエントリーへ。
NetServer実装の悩み
NetServerの送信がうまくいかない件
WinPcapを利用したデバイスドライバがread時にブロックしているのがだめだということが分かった。
pcap_open_liveの引数でタイムアウトを1msにして、readでタイムアウト時は0を返すようにしたら送信がうまくいくようになった。
その後、べた書きであれこれ整理したら、簡単なWebクライアントができた。
これは、サーバー内に実装されたべた書きなので、サーバーがAPIを提供しこれと同じ機能のものが、サーバー外で実装できなければならない。
uIPのイベントループはuip_flagsの状態を調べるマクロ(uip_connected, uip_ackedなど)をうまく使ってイベント処理をしなければいけないんだけれども、任意のクライアントに対してどうやってこれを開放すべきなんだろうか。
考え中。
次のステップとしては
- uip_xxxのイベントを意識したコードを書く。(サーバー内クライアント)
- イベント処理の流れが完全に把握できたら任意のクライアントに開放する仕組みを考える
という感じで。