進捗置き場というわけでもない場所

プログラミングしてる中で見つけたこととか

Siv3D上で動作するプロセス間通信ライブラリを作った

作っているものの関係でSiv3Dで動作するプロセス間通信ライブラリを組んだので、それの使い方とか概要を書いておく記事。

概要

名前はAzaika siv3D extention library、頭文字を取ってAselです。simple is best。
今のところ、他プロセスの制御とプロセス間通信機能があります。
しかし、他プロセス制御部分はちゃんと動いてないっぽいので、今回はプロセス間通信の方について書こうかと思います。

使い方

まずgithubからソースを落とします。
そしたら落としたソースの中にあるファイルを適当な場所にコピーし、Aselフォルダ内のcppを全てプロジェクトに追加します。
あとはAsel.hをincludeすれば使えるようになります。

使い方は適当なコードを見たほうが速いと思うのでそうします。
とりあえずサーバー側のコード

#include <Siv3D.hpp>
#include "Asel.h"

void Main() {
    const Font font(30);
    const String sendText = L"Kitty on your lap";
    bool hasSent = false;

    asel::Server server(L"aselTestServer");
    if (server) {
        server.start([&](asel::File& pipe) {
            pipe.write(sendText);
        });
    }

    while (System::Update()) {
        if (server) {
            font(L"Server: \n" + server.getName() + L"\nの構築に成功").draw();

            if (hasSent || server.hasConnected()) {
                server.update();
                hasSent = true;

                font(L"テキスト: " + sendText + L"\nを送信しました").draw({ 0, 170 });
            }
            else
                font(L"クライアントからの接続待機中").draw({0, 170});
        }
        else
            font(L"サーバーの構築に失敗").draw();
    }
}

そしてクライアント側のコード

#include <Siv3D.hpp>
#include "Asel.h"

void Main() {
    const Font font(30);
    String readStr = L"サーバーへの接続に失敗";
    auto client = asel::connectServer(L"aselTestServer");

    if (client) {
        auto str = client.read(17);
        if (str)
            readStr = *str;

        client.close();
    }

    while (System::Update()) {
        font(readStr).draw();
    }
}

こんな感じです。
コードだけで大体の流れは掴めるかと思います。
実行してみれば更に流れが掴めると思います。

…なんていう適当な紹介はこれまでにして、もうちょっと詳しく見ます。

まずサーバー側の

server.start([&](asel::File& pipe) {
    pipe.write(sendText);
});

この部分。
Server.start()は引数にasel::File&型を取り、voidを返す(何も返さない)関数を引数に取ります。ここでラムダ式を使うと便利ですね。
引数に渡した関数は、クライアントからの接続があるときにServer.update()すると呼ばれます。
asel::File型については後述。

次にクライアント側の

auto client = asel::connectServer(L"aselTestServer");

この部分。
asel::connectServer()は引数で渡された名前のサーバー(内部的にはパイプ)に接続し、asel::Fileを返す関数です。

さて、この2つに出てきたasel::File型というのは、誤解を恐れずいうとServerが持つ内部的なパイプの実体(のインターフェース)です。
asel::File型にはFile.read(int size)File.write(const String& str)関数が用意されており、
File.read(int size)はsize文字分の文字列を読み込みOptional<String>を、
File.write(const String& str)はパイプにstrを書き込みboolを返します。

これが大体の基本です。

しかし、一つ注意しなければならない点があります。
実行してみた人は気づいたと思いますが、asel::Serverコンストラクタasel::connectServerの引数に渡したサーバーの名前というのは簡略化されたもので、WinAPIの仕様上実際には先頭に\\.\pipe\のような文字列が付加されます。
この辺については色々と用意してあるので適当に使ってみてください。

また、ライブラリで用意されているほとんどの関数にはXMLコメントで解説を書いてあります。
ちょっと分からなくなったら見てみて下さい。

最後に

という感じです。

また、このライブラリはまだバグがあったり、仕様が甘かったりする点が大量にあると思うのでそういうのを見つけたらIssuesに上げるか作者Twitterまで言って(そしてあわよくばpull-reqを)下さい。多分直します。

というわけでオレオレライブラリの紹介でした。
もうちょっとだけオレオレライブラリの宣伝をすると、これをWinAPIでも使いたい人はwawlというWinAPIラッパライブラリを公開していますので使ってみてください。