自分のアプリを作りたいわけですが、まずはlibwebsocketsのサンプルプログラムを見てみます。libwebsockets\minimal-examples\ws-server\ 配下のディレクトリにサーバ側のサンプルプログラムがたくさんあり、何が何だかわかりにくいのですがminimal-ws-server、minimal-ws-server-echo、minimal-ws-server-pmdあたりを参考にしました。

要約すると、libwebsockets(以下、LWSと略す)のプログラムは、
struct lws_context_creation_info info;
という構造体を作り、そのinfoの各種パラメータを設定して、
struct lws_context *context = lws_create_context(&info);
を作ります。
そして、
lws_service(context, タイムアウト[ms]);
でサーバを起動します。
基本的にコールバックで動いていて、コールバックされる関数は
info.protocols = protocols;
でprotocolsという構造体の中にプロトコル名やバッファサイズと共に格納されています。
{ \
"protocol-name", \
callback_func, \
sizeof(struct per_session_data__minimal), \
128, \
0, NULL, 0 \
}
そして、このプロトコルは1つのサーバのポートに複数登録できます。例えば、HTTPと、独自のWebsocketプロトコルの2つという具合にです。
コールバック関数は以下のようなプロトタイプをしています。
static int callback_func(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
wsiというのはすべての情報が詰まったハンドルのようなもの。reasonがコールバックが呼び出された理由です。
処理するべきreasonは
- LWS_CALLBACK_PROTOCOL_INIT
- LWS_CALLBACK_PROTOCOL_DESTROY
- LWS_CALLBACK_ESTABLISHED
- LWS_CALLBACK_CLOSED
- LWS_CALLBACK_SERVER_WRITEABLE
- LWS_CALLBACK_RECEIVE
です。LWS_CALLBACK_PROTOCOL_INITは最初に呼び出され、lws_protocol_vh_priv_zalloc関数を使ってプロトコルごとに必要なローカルのメモリを確保します。リングバッファを作成したりするのもここです。LWS_CALLBACK_ESTABLISHEDは、通信のセッションが貼られると呼び出されます。
クライアントから何かデータを受信するとLWS_CALLBACK_RECEIVEが呼び出されます。inにlenバイトのデータが入っているのでmemcpyか何かして取り出します。
サーバからクライアントにデータを送るにはlws_write()を使うのですが、この関数はLWS_CALLBACK_SERVER_WRITEABLEの中で呼び出すようです。
つまり、何かのデータを受信して、それを処理してクライアントに応答を返したいという場合、RECEIVEの中で送信関数を呼び出すのではなく、次に送信可能になった時に送り出してもらうように登録するというふうにします。
登録するのが
lws_callback_on_writable(wsi);
で、呼び出されたLWS_CALLBACK_SERVER_WRITEABLEの中で
lws_write(wsi, バッファアドレス + LWS_PRE, 長さ, LWS_WRITE_TEXTまたはLWS_WRITE_BINARY);
とします。
気を付けなければならないのは、送信したデータが100バイトのときバッファは100+LWS_PRE(=16)バイトを確保しておく必要があり、送信データは&buf[LWS_PRE]から書き込んでおきます。websocketのデータにはヘッダが付くので、そのヘッダの分をバッファの先頭に付けれ置かなければならないようです。ユーザがヘッダを何かする必要はありません。mallocで確保したままの状態で構いません。
☀
さて、Javascriptからトリガを与えて、ZYNQ上のwebsocketサーバが応答を返すプログラムを作り、どのくらいのスループットが出るのかを試してみました。ZYNQ側はLAN9514接続の100BASE-TX、PC側はGitabitEtherです。

パケットサイズが1000バイトのときは0.8Mbyte、10kバイトのときは2.1MByte、100kバイトのときは2.2MByte、1Mバイトのときも2.2MByteでした。
すなわち、ZYNQのUSB経由の100Mイーサでも2.1~2.2Mバイト/秒の速度が出ていました。ボトルネックがZYNQのCPUの処理速度か、USB経由のLANか、ブラウザのJavascriptかはわかりませんが、手軽に動かすには十分な速度が出ると思っていいでしょう。
初期化の際のrx_buffer_sizeとtx_buffer_sizeをともに増やしてみました。転送速度は、
- フレームサイズ1000バイトのとき・・0.8MB/sec
- フレームサイズ1000バイトのとき・・3.8MB/sec
- フレームサイズ100kバイトのとき・・7.8MB/sec
- フレームサイズ1Mバイトのとき・・9.7MB/sec
・・ちょっと速すぎる気がします。
詳しいことは後日改めて計測することにしましょう。
最近のコメント