AI対戦サーバープログラム作成のヒント

その2 パイプを使ってみる

パイプとは?

コンピュータリテラシーなどでやったかもしれません。
パイプとは、

ls -l | more

のように、ある実行結果を別のものに渡す時に使いました。

windowsでは、専用のパイプを作成して、データのやり取りをします。
この回では、パイプを使用したデータのやり取りを扱います。

まずは使ってみよう

プログラムをみて、なんとなくでいいのでパイプの使い方の流れをつかんでみましょう。

main関数

まずはmain関数です。
特筆することはないですね。

#include <stdio.h>
#include <windows.h>

int execute();

int main()
{
  printf("start\n");

  int r = execute();

  printf("end\n");
  return r;
}

windows.hをインクルードしているくらいでしょうか。
パイプにも必要なので、忘れないでくださいね。

execute関数

さて本題の難しい方、パイプ通信を行うexecute関数です。
まずプログラムを眺めて、それから解説に移ります。

int execute(void)
{
  HANDLE readPipe  = NULL;
  HANDLE writePipe = NULL;
  // パイプの作成
  if (!CreatePipe(&readPipe, &writePipe, NULL, 0))
  { return -1; }

  // パイプへの書き込み
  const char message[] = "example-pipe";
  DWORD numberOfBytesWritten;
  if (!WriteFile(writePipe, message, strlen(message), &numberOfBytesWritten, NULL))
  { return -1; }

  // 書込パイプのクローズ
  if (!CloseHandle(writePipe))
  { return -1; }
  writePipe = NULL;

  // パイプからの読み込み
  while(1) {
    char buf[256+1];
    DWORD numberOfBytesRead;
    if (!ReadFile(readPipe, buf, sizeof(buf)-1, &numberOfBytesRead, NULL)) {
      if (GetLastError() == ERROR_BROKEN_PIPE) {
        printf("pipe end\n");
        break; //ループ終了
      }
      return -1;
    }
    buf[numberOfBytesRead] = '\0';
    printf("read=[%s]\n", buf);
  }

  // 読込パイプのクローズ
  if (!CloseHandle(readPipe))
  { return -1; }
  readPipe = NULL;

  return 0;
}

まず、CreatePipe関数でパイプを作成します。
ここでは、第1、第2引数にHANDLE型のアドレスを入れます。
ここに読み取り側、書き込み側のパイプが作成されます。
(3,4番目の引数はこのままでいいと思います)

次に、作成したパイプにwriteFile関数で書き込みをしています。
引数の前半部分は予想できると思いますが、順に書き込み先、書き込む内容、その文字数です。
第4引数には、DWORD型のアドレスを渡しますが、書き込む内容のバイト数が格納されることになります。
第5引数はNULLのままでいいでしょう。

書き込みが終了した時点で、書き込み用のパイプを閉じておきます。
パイプを閉じると、対応する読み込みパイプにはERROR_BROKEN_PIPEが送られます。

パイプからの読み込みには、ReadFile関数を使用します。
使う引数はWriteFile関数とほぼ同じなので省略します。
ただし、第3引数がパイプから受け取る最大文字数になるのでこれだけ注意してください。

無限ループの脱出条件は、ReadFileに失敗したら、となっています。
失敗の理由がERROR_BROKEN_PIPEなら無限ループをbreakし、それ以外は-1を返すことで強制終了しています。

最後に読み込み用のパイプも閉じて、この関数は終了しています。

実行結果

このプログラムを実行すると、次のような結果となります。

start
read=[example-pipe]
pipe end
end

パイプを使って送信したデータが正しく出力され、ERROR_BROKEN_PIPEによって通信が終了しているのがわかります。

次回

同じプログラムの中でパイプを使えるようになりました。
次回は親と子のプログラム間でパイプ通信を行います。

前回:なし 次回:パイプを使って通信する

コメント



トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS