C ++を使用してnode.jsの非同期モジュールを作成する

Node.jsが開発中であり、グラフィカルアプリケーションまたはいくつかのコンソールユーティリティとサービスの作成を実験することは既に可能です。 開発プロセスでは、WMI(node.jsからWMIに直接アクセスできず、WMI要求が長くなり、イベントループがブロックされたり、Web経由で接続している場合など)ソケット、通信が中断する場合があります)。 いくつかのオプションがあります。 モジュール(たとえば、node-ffi)を使用して、それを試してみることができます。 方法、より正確には、松葉杖がまだあります。 Windowsには、いわゆるWScript(Windows Script Host)があります-これは、JScript、VBScriptなどを実行するように設計されたWindowsコンポーネントです。 JScriptはWMIに直接アクセスできるため、child_processを実行してJScriptが動作し、そこからデータを受信(たとえば、JSONを生成して文字列として送信)できますが、これは松葉杖で、意味がなく、容赦ないものです。 3番目の方法は、ネイティブモジュールです。 WMIからデータを取得する方法については説明しませんが、容量の少ないものについては説明します。 誰が気にする-私は猫をお願いします。



UPD:環境のセットアップ


VS2010のコンパイルと構成に使用しました。



まず、ソースnode.jsをダウンロードし、ルートにあるvcbuild.batを解凍して実行します。 vcbuild.batは、Visual Studioと構成に必要なプロジェクトを作成します。 バッチファイルを機能させるには、Python 2.7が必要です。 次に、 npm install node-gyp







次に、Visual Studioでプロジェクト(CLR Empty Project)を作成し、プロジェクトプロパティに移動し、構成タイプを.dllに、拡張子を.nodeに変更し、CLR環境サポートをインストールします。 ディレクトリセクションに移動し、包含ディレクトリで次のフォルダへのパスを追加します

node-v0.8.15\deps\v8\include







node-v0.8.15\deps\uv\include







node-v0.8.15\src









次に、ソースコードファイルを追加します。 この段階で、VS(オプション)を終了して、お気に入りのNotepad / Sublime / WebStormを開くことができます。

次に、ソースディレクトリに移動し、そこにbinding.gypファイルを作成します。このファイルは、node-gypユーティリティにアプリケーションのビルド方法とビルド元を伝えます。 私の例では、それは非常にシンプルで簡単です。

 { "targets": [ { "target_name": "getSummAsync", "sources": [ "async.cpp" ] } ] }
      
      







これでコンパイルできます。 binding.gypという行にnode-gyp configure



node-gyp configure



したディレクトリにコンソールで書き込み、次にnode-gyp build





コンパイルされたモジュールはbuild / Releaseフォルダーになります



例自体


システムコールは使用しません。 これには特別な意味はありません。例が複雑になるだけです。 それでは、始めましょう。



たとえば、整数の配列を渡し、その合計をカウントし、正の要素を取得してユーザーに返します。



まず、構造体を宣言し、その構造体で必要なデータ構造体を宣言します。



 struct Summ_req { vector<int> numbers; vector<int> gtz; int result; Persistent<Function> callback; };
      
      





これは、数値を格納するベクトルです。

 vector<int> numbers;
      
      





ゼロより大きい数値を格納するベクトル。

 vector<int> gtz;
      
      





ここに結果を保存します

 int result;
      
      







ベクトルを使用する理由を理解することは重要ですが、標準のv8テンプレートでうまくいくようです。 しかし、これはそうではありません。 詳細については、以下をご覧ください。



モジュールには、node.jsから呼び出すメイン関数と、実際にはモジュールを非同期にする他の2つの3つの関数があります。

仕事関数

getSummAsyncは、要素の配列とコールバックの2つの引数を受け入れます。 関数が呼び出されるパラメーターが正しいかどうかを確認します。パラメーターが正しい場合はカスタマイズします。つまり、引数と通信できるようにするには、目的の型に変換する必要があります。



 Local<Function> callback = Local<Function>::Cast(args[1]); Local<Array> numbers = Local<Array>::Cast(args[0]);
      
      







次に、構造体を初期化してコールバックを渡し、配列をベクターに書き込みます。

 Summ_req* request = new Summ_req; request->callback = Persistent<Function>::New(callback); for (size_t i = 0; i < numbers->Length(); i++) { request->numbers.push_back(numbers->Get(i)->Int32Value()); }
      
      







永続性が望ましいのは、 それでも、この関数だけでなくコールバックも使用されます。



そして、ワーカーを順番に起動します。

 uv_queue_work(uv_default_loop(), req, Worker, After);
      
      





getSummAsync
 static Handle<Value> getSummAsync (const Arguments& args) { HandleScope scope; if (args.Length() < 2 || !args[0]->IsArray()) { return ThrowException(Exception::TypeError(String::New("Bad arguments"))); } if (args[1]->IsFunction()) { Local<Function> callback = Local<Function>::Cast(args[1]); Local<Array> numbers = Local<Array>::Cast(args[0]); Summ_req* request = new Summ_req; request->callback = Persistent<Function>::New(callback); for (size_t i = 0; i < numbers->Length(); i++) { request->numbers.push_back(numbers->Get(i)->Int32Value()); } uv_work_t* req = new uv_work_t(); req->data = request; uv_queue_work(uv_default_loop(), req, Worker, After); } else { return ThrowException(Exception::TypeError(String::New("Callback missing"))); } return Undefined(); }
      
      







ワーカー機能では、すべてが明確だと思います。 数値をカウントし、結果を構造に返します。 次に、v8ツールではなくベクターを使用する理由について説明します。 Worker関数は別のスレッドで動作し、node.jsとv8では1つのスレッドのみがjsを実行できます。つまり、別のスレッドでv8配列を作成することはできません。



労働者
 void Worker(uv_work_t* req) { Summ_req* request = (Summ_req*)req->data; request->result = 0; for (vector<int>::iterator it = request->numbers.begin(); it != request->numbers.end(); ++it) { request->result += *it; if (*it > 0) { request->gtz.push_back(*it); } } // request->result = request->int1 + request->int2; }
      
      







これでAfter関数です。 Workerが機能した後、After関数が呼び出されます。この関数は既にnode.jsにデータを返すことができます。

ここで、Worker関数ではなく、上記で説明した理由により、結果の配列を取得します。

  Handle<Value> argv[2];
      
      





ここに戻り値を入れます

  request->callback->Call(Context::GetCurrent()->Global(), 2, argv);
      
      





そして、argvに書き込まれたパラメーターを使用してコールバックを呼び出します。

 void After(uv_work_t* req) { HandleScope scope; Summ_req* request = (Summ_req*)req->data; delete req; Handle<Value> argv[2]; argv[0] = Integer::New(request->result); Local<Array> gtz = Array::New(); size_t i = 0; for (vector<int>::iterator it = request->gtz.begin(); it != request->gtz.end(); ++it) { gtz->Set(i, Integer::New(*it)); i++; } argv[1] = gtz; TryCatch try_catch; request->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { FatalException(try_catch); } request->callback.Dispose(); delete request; }
      
      







node-gypユーティリティを使用してコンパイルした後、node.jsからモジュールを呼び出すことができます。

 var foo = require('./getSummAsync.node') foo.getSummAsync([1,2,3,6,-5],function(a, b){ console.log(a, b); });
      
      





結果

7 [ 1, 2, 3, 6 ]









これは私の最初の記事です、私をあまりscらないでください。

ご質問がある場合は、お問い合わせください!

参照資料




All Articles