新規記事の投稿を行うことで、非表示にすることが可能です。
2015年01月26日
いまさらながらの Mailslot
近頃セッション境界を越えてメッセージを送信したい要求が出てきて、やりたいことと仕掛けのバランスがよいものを探していたのだが、ふと、昔読んだ本の内容を思い出し、メールスロットなるものを使ってみた
元々の要求は、異なるプロセスから一方向でメッセージを送信したいというもので、普通にやるなら引数と SendMessage で済む程度の簡単なものなのだったが、セッション境界を越えて渡せないことに気が付き、はたと困ったのであった
こうした欲求を満たすには、大掛かりなものでは TCP で TELNET プロトコルを実装するなどをしてきたのだが、ポートの割り当て問題などがあり、ちょっと面倒
名前付きパイプが妥当そうに見えたのだが、API がごちゃごちゃしていて、あまり使い勝手がよくないと感じた(双方向通信なら、こちらがいいかもしれない)
そこで、一方向で済む、メールスロットを思い出したのだが、そもそもこの機構はかなり古い時代から存在するので、今では DDE のように化石扱いなのではないかと心配になった
API の解説を読む限りは、シンプルで最低限のセキュリティを備えているので、まだまだ現役で使えそうではある
サーバの簡単な実装は以下のようである
途中、
一方、クライアント側は単純にファイルに書き込むだけでよい
以下のよう
実に単純な構成だが、セッション超えには実はもう一つ落とし穴があった
元々の要求は、異なるプロセスから一方向でメッセージを送信したいというもので、普通にやるなら引数と SendMessage で済む程度の簡単なものなのだったが、セッション境界を越えて渡せないことに気が付き、はたと困ったのであった
こうした欲求を満たすには、大掛かりなものでは TCP で TELNET プロトコルを実装するなどをしてきたのだが、ポートの割り当て問題などがあり、ちょっと面倒
名前付きパイプが妥当そうに見えたのだが、API がごちゃごちゃしていて、あまり使い勝手がよくないと感じた(双方向通信なら、こちらがいいかもしれない)
そこで、一方向で済む、メールスロットを思い出したのだが、そもそもこの機構はかなり古い時代から存在するので、今では DDE のように化石扱いなのではないかと心配になった
API の解説を読む限りは、シンプルで最低限のセキュリティを備えているので、まだまだ現役で使えそうではある
サーバの簡単な実装は以下のようである
HANDLE g_hServer = CreateMailslotW(SERVER_NAME, MESSAGE_SIZE, SERVER_TIMEOUT, NULL);
while (true) {
DWORD cnt = 0;
if (!GetMailslotInfo(g_hServer, NULL, NULL, &cnt, NULL)) {
fprintf(stderr, "GetMailslotInfo failed by %d\n", GetLastError());
break;
}
if (cnt > 0) {
CHAR szMessage[MESSAGE_SIZE+1] = {0};
DWORD dwRead;
OVERLAPPED ovl = {0};
ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
BOOL rc = ReadFile(g_hServer, szMessage, MESSAGE_SIZE, &dwRead, &ovl);
CloseHandle(ovl.hEvent);
if (!rc) {
fprintf(stderr, "ReadFile failed by %d\n", GetLastError());
break;
}
printf("%s\n", szMessage);
}
Sleep(100);
}
CloseHandle(g_hServer);
途中、
if (cnt > 0)
としてあるところは、 for (DWORD j = 0; j < cnt; j++)
とすべきかもしれない一方、クライアント側は単純にファイルに書き込むだけでよい
以下のよう
HANDLE hFile = CreateFile(SERVER_NAME, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
fprintf(stderr, "CreateFile failed by %d\n", GetLastError());
return 1;
}
CHAR szMessage[] = "Hello world";
DWORD dwSize;
if (!WriteFile(hFile, szMessage, strlen(szMessage), &dwSize, NULL)) {
fprintf(stderr, "WriteFile failed by %d\n", GetLastError());
}
CloseHandle(hFile);
実に単純な構成だが、セッション超えには実はもう一つ落とし穴があった