新規記事の投稿を行うことで、非表示にすることが可能です。
2016年05月22日
CentOS7 で Tomcat のポートを解放する Firewall 設定方法
CentOS7 を試しにインストールしてみたのだが、いつもよく使う tomcat を運用しようとしたら、 Firewall で止められたままだった。 CentOS6 では GUI のツールがあり、そこで設定していたのだが、どうも見当たらない。
/etc/sysconfig/iptables ファイルを編集すればいいのか?とも思ったのだが、そのファイルも見当たらない。。。
やはり、管理方式が変わったようなので、WEB で調べてみた。
ここに詳しく書いてあるのだが、やりたいことに即して、簡単にまとめておく
やりたいこと
大まかな手順としては、 /usr/lib/firewalld/services/ 以下に .xml ファイルを準備し、そのファイルを firewall-cmd というコマンドで登録、サービス再起動ということのようだ
手順
※以下はすべて root 権限で実行する必要がある
※tomcat.xml は存在しないので新たに作成する必要がある
※http.xml , https.xml は既に用意されているので作成する必要はない
tomcat.xml の内容
これで、 80, 443, 8080 のポートが解放され、他のホストから接続することができるようになる
めでたし、めでたし
お名前.comの高性能VPS
/etc/sysconfig/iptables ファイルを編集すればいいのか?とも思ったのだが、そのファイルも見当たらない。。。
やはり、管理方式が変わったようなので、WEB で調べてみた。
ここに詳しく書いてあるのだが、やりたいことに即して、簡単にまとめておく
やりたいこと
- tomcat のポート (8080) を開く
- Apache のポート (80, 443) を開く
大まかな手順としては、 /usr/lib/firewalld/services/ 以下に .xml ファイルを準備し、そのファイルを firewall-cmd というコマンドで登録、サービス再起動ということのようだ
手順
※以下はすべて root 権限で実行する必要がある
※tomcat.xml は存在しないので新たに作成する必要がある
※http.xml , https.xml は既に用意されているので作成する必要はない
- tomcat.xml を作成する
- firewall-cmd --zone=public --permanent --add-service=tomcat
- firewall-cmd --zone=public --permanent --add-service=http
- firewall-cmd --zone=public --permanent --add-service=https
- systemctl restart firewalld.service
tomcat.xml の内容
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>Tomcat</short>
<description>Open Tomcat port</description>
<port protocol="tcp" port="8080"/>
</service>
これで、 80, 443, 8080 のポートが解放され、他のホストから接続することができるようになる
めでたし、めでたし
お名前.comの高性能VPS
タグ:CentOS7
2016年03月16日
タスクバー(タスクトレイ)上のアプリアイコンで進捗状況表示
久々にクライアントアプリの開発をすることになった。
ネットワーク越しにファイル変換を行って、変換後のデータをもらい、ファイルに保存するという割と単純なものだが、ファイルサイズによっては時間がかかる場合もある。
そこでUI的に進捗状況を表示したいと思ったが、ダイアログ上にプログレスバーを表示するのは実装してみたが、何かしっくりこないので、別のインターフェースを模索していたら、Windows7以降で追加された、タスクバー上でのアイコンがプログレスバーのように変化するアプリがあるのを思い出し、まねをしてみようと思い立った。
WEBで検索してみると、ITaskBar3 インターフェースを使えばできそうということがわかった。
ITaskbarList3::SetProgressState
ところが、MSDNのどこにも、 ITaskbarList3 のインスタンスの取得方法が書いていなかった。
昔、こうした状況だと、グローバル関数でインスタンスを作成していたという記憶があるのだが、どうも対応する生成関数などが見当たらない。
Excel のインスタンスを取得する際は、 CoGetClassObject を使えばいいはず、ということから、関連で調べていくと、 単純に CoCreateInstance すればいいのではないかということになったのだった。
ようやく、コードが作成でき、以下のような関数を作成して呼び出すようにしてみた
上記コードはマーキースタイルのプログレス表示で、開始と停止があるだけなので、使い方も簡単である
開始 setup_taskbar_marquee(hWnd, true)
停止 setup_taskbar_marquee(hWnd, false)
できてみればさほど難しいコードではないのだが、最初がわかるまでは結構調べるのに時間がかかってしまうものだ
これで見た目も、最近のアプリっぽくなり (もう古いか?) めでたし、めでたし
完全仮想化方式のVPS
ネットワーク越しにファイル変換を行って、変換後のデータをもらい、ファイルに保存するという割と単純なものだが、ファイルサイズによっては時間がかかる場合もある。
そこでUI的に進捗状況を表示したいと思ったが、ダイアログ上にプログレスバーを表示するのは実装してみたが、何かしっくりこないので、別のインターフェースを模索していたら、Windows7以降で追加された、タスクバー上でのアイコンがプログレスバーのように変化するアプリがあるのを思い出し、まねをしてみようと思い立った。
WEBで検索してみると、ITaskBar3 インターフェースを使えばできそうということがわかった。
ITaskbarList3::SetProgressState
ところが、MSDNのどこにも、 ITaskbarList3 のインスタンスの取得方法が書いていなかった。
昔、こうした状況だと、グローバル関数でインスタンスを作成していたという記憶があるのだが、どうも対応する生成関数などが見当たらない。
Excel のインスタンスを取得する際は、 CoGetClassObject を使えばいいはず、ということから、関連で調べていくと、 単純に CoCreateInstance すればいいのではないかということになったのだった。
ようやく、コードが作成でき、以下のような関数を作成して呼び出すようにしてみた
void setup_taskbar_marquee(HWND hWnd, bool bStart)
{
CComPtrpUnk;
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList, (LPVOID*)&pUnk);
if (SUCCEEDED(hr)) {
CComQIPtrtbl(pUnk);
if (tbl) {
CComQIPtrtbl3(tbl);
if (tbl3) {
if (bStart) {
tbl3->SetProgressState(hWnd, TBPF_INDETERMINATE);
} else {
tbl3->SetProgressState(hWnd, TBPF_NOPROGRESS);
}
}
}
}
}
上記コードはマーキースタイルのプログレス表示で、開始と停止があるだけなので、使い方も簡単である
開始 setup_taskbar_marquee(hWnd, true)
停止 setup_taskbar_marquee(hWnd, false)
できてみればさほど難しいコードではないのだが、最初がわかるまでは結構調べるのに時間がかかってしまうものだ
これで見た目も、最近のアプリっぽくなり (もう古いか?) めでたし、めでたし
完全仮想化方式のVPS
2015年08月27日
レジストリの Wow6432Node へのリダイレクト条件
64ビットOS上で実行される32ビット実行ファイルから見えるレジストリツリーは Wow6432Node 以下になるというのは、64ビット開発を始めた頃に知ったのだが、必ずしもそうとは限らない状況があることがわかった
たまたま、32ビットコンパイルした実行ファイルを Windows8.1 (64bit) 上でデバッグしていた際、レジストリから情報を取得するルーチンで、値が取れていないことが判明、よく見たら、32ビット環境から見える HKLM\SOFTWARE\Wow6432Node 以下には確かに値を設定していないことがわかった
例えば以下のコードを実行しようとすると
これと同じスキームで、HKCU にアクセスしている箇所のキーを、Wow6432Node 以下に作成したら、見つからないという現象に見舞われた
こんな仕様だったっけ?と思い調べなおしたら、以下の解説が見つかった
https://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
要するに、Wow6432Node にリダイレクトされるものとそうでないものが決まっているということだった
こうした情報を見逃していたのだった(恥ずかしい)
たまたま、32ビットコンパイルした実行ファイルを Windows8.1 (64bit) 上でデバッグしていた際、レジストリから情報を取得するルーチンで、値が取れていないことが判明、よく見たら、32ビット環境から見える HKLM\SOFTWARE\Wow6432Node 以下には確かに値を設定していないことがわかった
例えば以下のコードを実行しようとすると
HKEY hKey;実際には HKLM\Software\Wow6432Node\MyCompany\Information キーが開かれる
LONG lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\MyCompany\\Information"), 0, KEY_QUERY_VALUE, &hKey);
これと同じスキームで、HKCU にアクセスしている箇所のキーを、Wow6432Node 以下に作成したら、見つからないという現象に見舞われた
HKEY hKey;コード上はおかしくないのだが、もしかしたらと思って、HKCU\Software\MyCompany\Information に値を設定したら正しく読み込めたのだった
LONG lRes = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\MyCompany\\Information"), 0, KEY_QUERY_VALUE, &hKey);
こんな仕様だったっけ?と思い調べなおしたら、以下の解説が見つかった
https://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
要するに、Wow6432Node にリダイレクトされるものとそうでないものが決まっているということだった
こうした情報を見逃していたのだった(恥ずかしい)
2015年07月26日
.pdb から .map ファイルを作成する
VS2012 を使用するようになってから、通常、デバッグビルド、リリースビルド共に、実行ファイルと .pdb ファイルが生成されるように運用してきたが、ふと、アプリケーションエラー時にどのアドレスで落ちたかを知るための手掛かりを得る .map ファイルを生成すべきかどうかが気になった
以前(VS6を利用してきた期間が長い)はリリースビルド時には、.pdb ファイルではなく .map ファイルを生成していたのだが、VS2012 に移行した際に、自動的に上記のような状況になっていた
最近までは特に気にしていなかったのだが、デバッガが無い状況で、アプリケーションエラーのアドレスだけ示されたときにどう追いかければいいのかが、ふと気になってしまった
そこで改めて調べてみたら、実行ファイルと .pdb ファイルがあれば、 .map ファイルを生成できることがわかったので、メモしておく
ところが、この /map オプションが MSDN ドキュメントにも、 dumpbin /? としても、出てこないのだ
見つけたのは、stackoverflow の投稿記事の応答の中である
オリジナルのソースが今のところ不明であるが、実際上出力内容は .map ファイル内容とほぼ同じである
違いとしては、通常コンパイルオプションで生成する .map ファイルは、リンクされた関数本体がどの .obj ファイル由来(どの .lib 由来)であるかがわかりやすい
一方、dumpbin の出力では、各関数のサイズがわかりやすいという違いがある
一般的には関数のエントリポイントとエントリポイントの間のどこかで例外となるので、サイズがわかる方が便利かもしれない
ただ、常に .map を生成するようにしておくと、ディスク容量がもったいないので、現状のように .pdb だけ生成しておき、必要になったら .map 情報を生成して調査する方がいいと思う
★☆★☆★☆ ナウでヤングなレンタルサーバー!ロリポップ! ☆★☆★☆★
月額100円(税抜)〜容量最大400GB!大人気のWordpressも簡単インストール★
海外向けのネットショップ作成サービスならJugem Cart
以前(VS6を利用してきた期間が長い)はリリースビルド時には、.pdb ファイルではなく .map ファイルを生成していたのだが、VS2012 に移行した際に、自動的に上記のような状況になっていた
最近までは特に気にしていなかったのだが、デバッガが無い状況で、アプリケーションエラーのアドレスだけ示されたときにどう追いかければいいのかが、ふと気になってしまった
そこで改めて調べてみたら、実行ファイルと .pdb ファイルがあれば、 .map ファイルを生成できることがわかったので、メモしておく
dumpbin /map appl.exe > appl.map
ところが、この /map オプションが MSDN ドキュメントにも、 dumpbin /? としても、出てこないのだ
見つけたのは、stackoverflow の投稿記事の応答の中である
オリジナルのソースが今のところ不明であるが、実際上出力内容は .map ファイル内容とほぼ同じである
違いとしては、通常コンパイルオプションで生成する .map ファイルは、リンクされた関数本体がどの .obj ファイル由来(どの .lib 由来)であるかがわかりやすい
一方、dumpbin の出力では、各関数のサイズがわかりやすいという違いがある
一般的には関数のエントリポイントとエントリポイントの間のどこかで例外となるので、サイズがわかる方が便利かもしれない
ただ、常に .map を生成するようにしておくと、ディスク容量がもったいないので、現状のように .pdb だけ生成しておき、必要になったら .map 情報を生成して調査する方がいいと思う
★☆★☆★☆ ナウでヤングなレンタルサーバー!ロリポップ! ☆★☆★☆★
月額100円(税抜)〜容量最大400GB!大人気のWordpressも簡単インストール★
海外向けのネットショップ作成サービスならJugem Cart
2015年05月29日
LDAP 検索の分割アクセス
登録済みユーザの一覧を作成するなどの場合、いっぺんにアクセスしてしまうと、メモリの問題を引き起こしたりする可能性があるので、件数を区切って分割アクセスしたい場合がある
javax.naming.ldap.PagedResultsControl をLDAPコンテキスト (javax.naming.ldap.LdapContext) に対して追加してやればできるようになる
しかも Java ドキュメント にサンプルコードも掲載されており、非常に助かる
ポイントは、初回は null である byte[] javax.naming.ldap.PagedResultsResponseControl#getCookie() の値が null になるまで繰り返すということだ
こうしないと無限ループになったり、初回ページしかアクセスできなかったりということになる
おおざっぱな構造を示すと以下のようになる
これでめでたくページアクセスできるようになった
最初から件数がわかっているようなものであれば、こうしなくても大丈夫であろうが、検索結果が想定以上(導入当初は1000件程度だったものが、運用後1億件程度に膨れたなど)になった場合でも耐えうるコードが書けるだろう
★☆★☆★☆ ナウでヤングなレンタルサーバー!ロリポップ! ☆★☆★☆★
月額100円(税抜)〜容量最大400GB!大人気のWordpressも簡単インストール★
javax.naming.ldap.PagedResultsControl をLDAPコンテキスト (javax.naming.ldap.LdapContext) に対して追加してやればできるようになる
しかも Java ドキュメント にサンプルコードも掲載されており、非常に助かる
ポイントは、初回は null である byte[] javax.naming.ldap.PagedResultsResponseControl#getCookie() の値が null になるまで繰り返すということだ
こうしないと無限ループになったり、初回ページしかアクセスできなかったりということになる
おおざっぱな構造を示すと以下のようになる
// LDAP コンテキストを生成
LdapContext context = new InitialLdapContext();
// 初回クッキーは null
byte[] cookie = null;
// ページサイズ
int pageSize = 100;
// ページ制御をコンテキストに追加
context.setRequestControls(new Control[]{new PagedResultControl(pageSize, Control.CRITICAL);
do {
NamingEnumeration en = context.search(検索オプション);
// 検索結果の処理(pageSize 分だけループすることになるだろう)
...
// セットしたはずの PagesResultResponseControl を探し出してクッキー値を取得する
// 具体的なコードはマニュアルページに書いてあるが、Control 配列から見つけ出すという手法
PagedResultControl ctl = findPagedResultControl(context);
cookie = ctl.getCookie();
// 次回アクセスのために再度 PagedResultControl をセットする
context.setRequestControls(new Control[]{new PagedResultControl(pageSize, cookie, Control.CRITICAL);
} while (null != cookie);
これでめでたくページアクセスできるようになった
最初から件数がわかっているようなものであれば、こうしなくても大丈夫であろうが、検索結果が想定以上(導入当初は1000件程度だったものが、運用後1億件程度に膨れたなど)になった場合でも耐えうるコードが書けるだろう
★☆★☆★☆ ナウでヤングなレンタルサーバー!ロリポップ! ☆★☆★☆★
月額100円(税抜)〜容量最大400GB!大人気のWordpressも簡単インストール★
2015年04月13日
今更知った文字列比較の落とし穴
先日、自前のISAMシステムを開発していたのだが、インデックス構築側(仮にサーバサイド)では見つかるのに、検索側(仮にクライアントサイド)では見つからないという奇妙な現象が発生した
よくよくしらべてみると、サーバサイドではソートの際にキーの比較に strcmp を使用しているのに対し、クライアントサイドでは stricmp を使用しているのに気が付いた
元々のインデックスはすべて大文字変換してから格納してあったので、両者に違いはないと思いこんでいたのだが、実はここが大きな落とし穴で、stricmp のMSDNでの仕様は、小文字に変換してから比較するという記述があったのだ
そこでは、サンプルとしてアンダースコア '_' を含む文字列比較が、 strcmp と stricmp とで異なる結果を返すという解説も記述してあった
そこで、クライアントサイド側でデバッグしてみると、確かに、 '_' を含むデータの個所で、インデックス判定が逆転するということがわかった(検索では bsearch_s API を利用していたので、大小が逆転すると見つからなくなってしまう)
以前の記憶(おそらくVC6時代)では、stricmp は大文字変換してから比較していると思いこんでいたので、今回も、あえてインデックスは大文字変換してから格納していたのだが、それが裏目に出た格好だ
これについては、クライアントサイドのコードを修正し、キーとターゲットを両方大文字に変換してから strcmp を使うことで正しい結果を得ることができた
いや〜、長年の思い込みは怖いですね
よくよくしらべてみると、サーバサイドではソートの際にキーの比較に strcmp を使用しているのに対し、クライアントサイドでは stricmp を使用しているのに気が付いた
元々のインデックスはすべて大文字変換してから格納してあったので、両者に違いはないと思いこんでいたのだが、実はここが大きな落とし穴で、stricmp のMSDNでの仕様は、小文字に変換してから比較するという記述があったのだ
そこでは、サンプルとしてアンダースコア '_' を含む文字列比較が、 strcmp と stricmp とで異なる結果を返すという解説も記述してあった
そこで、クライアントサイド側でデバッグしてみると、確かに、 '_' を含むデータの個所で、インデックス判定が逆転するということがわかった(検索では bsearch_s API を利用していたので、大小が逆転すると見つからなくなってしまう)
以前の記憶(おそらくVC6時代)では、stricmp は大文字変換してから比較していると思いこんでいたので、今回も、あえてインデックスは大文字変換してから格納していたのだが、それが裏目に出た格好だ
これについては、クライアントサイドのコードを修正し、キーとターゲットを両方大文字に変換してから strcmp を使うことで正しい結果を得ることができた
いや〜、長年の思い込みは怖いですね
2015年03月09日
MS Office のクリップアートサービスがいつの間にかなくなっていた
久しぶりに PowerPoint でチャート図でも作ろうとしたのだが、図やアイコンなどは手作業で作るのも面倒なので、いつもはMSが提供しているクリップアートを利用していた
今回も何も気にせずいつのもようにやろうとしたら、なぜだか、いつもの画面にならない
あれこれ操作してみたが、右側に出る「作業なんたら。。。」というペインが出ない
もしや、2010から2013に乗り換えたので、操作が変わったのかなと思い、「オンライン画像」→「オンライン画像」とやってみても、以下のような画面になるだけである
以前は、キーワードで検索できていたと思うのだが。。。
WEB で検索してみたら、以下の記事が見つかった
Microsoft、Officeの「クリップアート」提供を終了 Bingイメージ検索に
な〜んと、もはや使えなくなってしまっていた
近頃では、アプリの機能をネット越しに提供することが増えているが、昔ながらのオフラインアプリとは異なり、サービスがなくなってしまうと、アプリの機能も損なわれてしまうということだ
これでは、高い金を払って購入(しかも期限付きだったりする)したのに、裏切られた(だまされた?)という気分だ
MSDN での日本語解説があてにならないのと同様、金を払っても、払った金の分だけのサービスを受けれなくなるのが当たり前の世の中になってしまったのだろうか?
今回も何も気にせずいつのもようにやろうとしたら、なぜだか、いつもの画面にならない
あれこれ操作してみたが、右側に出る「作業なんたら。。。」というペインが出ない
もしや、2010から2013に乗り換えたので、操作が変わったのかなと思い、「オンライン画像」→「オンライン画像」とやってみても、以下のような画面になるだけである
以前は、キーワードで検索できていたと思うのだが。。。
WEB で検索してみたら、以下の記事が見つかった
Microsoft、Officeの「クリップアート」提供を終了 Bingイメージ検索に
な〜んと、もはや使えなくなってしまっていた
近頃では、アプリの機能をネット越しに提供することが増えているが、昔ながらのオフラインアプリとは異なり、サービスがなくなってしまうと、アプリの機能も損なわれてしまうということだ
これでは、高い金を払って購入(しかも期限付きだったりする)したのに、裏切られた(だまされた?)という気分だ
MSDN での日本語解説があてにならないのと同様、金を払っても、払った金の分だけのサービスを受けれなくなるのが当たり前の世の中になってしまったのだろうか?
2015年02月10日
いまさらながらの Mailslot 【続き】
前回は MailSlot を使うための基本構成を示したのだが、実際にやりたいことは、他のデスクトップ、多くは異なるセキュリティコンテキスト(つまりは異なるユーザなど)からも通知を受けたいということであった
そうすると、前回のサーバ側の実装では、同じユーザコンテキストからしか通知を受けれないということになってしまう
それを解決するのは、実は簡単で、セキュリティ属性(SECURITYP_ATTRIBUTES)を渡せばいいだけなのだった
改善したサーバ側の実装例
今回はコードを簡潔にするために ATL のセキュリティ関連テンプレートを利用してみた
ATL を使いたくなければ、地道に構造体を初期化して、セキュリティコンテキスト名から SID を求めて、などの作業が必要となる(わかってしまえば、それほどのコードではないのだが、自分はいつも一発では書けないので、面倒だと感じている)
これでめでたく当初の目的は果たせることになった
ただし、今回は Sids::World() を利用したが、セキュリティを考慮し、もっと限定的な SID を利用することも可能だし、そうすべきかもしれない
そうすると、前回のサーバ側の実装では、同じユーザコンテキストからしか通知を受けれないということになってしまう
それを解決するのは、実は簡単で、セキュリティ属性(SECURITYP_ATTRIBUTES)を渡せばいいだけなのだった
改善したサーバ側の実装例
CDacl dacl;
dacl.AddAllowedAce(Sids::World(), FILE_ALL_ACCESS);
CSecurityDesc sd;
sd.SetDacl(dacl);
CSecurityAttributes sa(sd);
HANDLE g_hServer = CreateMailslot(SERVER_NAME, MESSAGE_SIZE, SERVER_TIMEOUT, &sa);
今回はコードを簡潔にするために ATL のセキュリティ関連テンプレートを利用してみた
ATL を使いたくなければ、地道に構造体を初期化して、セキュリティコンテキスト名から SID を求めて、などの作業が必要となる(わかってしまえば、それほどのコードではないのだが、自分はいつも一発では書けないので、面倒だと感じている)
これでめでたく当初の目的は果たせることになった
ただし、今回は Sids::World() を利用したが、セキュリティを考慮し、もっと限定的な SID を利用することも可能だし、そうすべきかもしれない
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);
実に単純な構成だが、セッション超えには実はもう一つ落とし穴があった
2014年09月03日
Firebird で外部DBにレコードを同期的に追加する
最新の Firebird 2.5.3 では、リモートDBに対して操作できる機能も追加されていることを知り、データの同期に使えることがわかった
直接やりたかったことは、マスターテーブルに対してログレコードを出力した際に、別のバックアップDBに対しても同じレコードを出力したいということだった
つまり、HOST_A の LOGTABLE に対して INSERTされたら、HOST_B の LOGTABLE にも INSERT したいということ
これを実現するために、HOST_A の LOGTABLE に対して以下のようなトリガーを設定すればよい
これでめでたく、レコードの同期ができることになった
※ただし、INSERTのみ、いわゆる完全なレプリケーション機能とは異なる
※もっとも、各種トリガーを定義すれば、かなりそれに近いことはできそうだが、設定がかなり面倒だ
【広告】
国内最大級の個人向けレンタルサーバー『ロリポップ!レンタルサーバー』は、
月額100円(税抜)〜で容量最大120GB!しかも安いだけじゃなく
大人気WordPressの簡単インストール/ウェブメーラーなど
機能も満載!共有/独自SSLもバッチリ対応でセキュリティ対策も万全!
もちろん、オンラインマニュアルやライブチャットなど、
充実したサポートで初心者の方でも安心です。
無料のお試し期間が10日間ありますので、
まずはお気軽にご利用してみてくださいね!
▼ロリポップ!レンタルサーバーはこちら
お名前.com レンタルサーバー
直接やりたかったことは、マスターテーブルに対してログレコードを出力した際に、別のバックアップDBに対しても同じレコードを出力したいということだった
つまり、HOST_A の LOGTABLE に対して INSERTされたら、HOST_B の LOGTABLE にも INSERT したいということ
これを実現するために、HOST_A の LOGTABLE に対して以下のようなトリガーを設定すればよい
CREATE TRIGGER ON_INSERT_LOGTABLE FOR LOGTABLE
AS
DECLARE sqlstr VARCHAR(128);
DECLARE rmtdb VARCHAR(128) = 'HOST_B:MY_DB.fdb';
DECLARE usernm VARCHAR(32) = 'sysdba';
DECLARE passwd VARCHAR(32) = 'masterkey';
BEGIN
sqlstr = 'INSERT INTO LOGTABLE VALUES(?)';
EXECUTE STATEMENT (:sqlstr) (new.DATA)
ON EXTERNAL DATA SOURCE :rmtdb
AS USER :usernm PASSWORD :passwd;
END
これでめでたく、レコードの同期ができることになった
※ただし、INSERTのみ、いわゆる完全なレプリケーション機能とは異なる
※もっとも、各種トリガーを定義すれば、かなりそれに近いことはできそうだが、設定がかなり面倒だ
【広告】
国内最大級の個人向けレンタルサーバー『ロリポップ!レンタルサーバー』は、
月額100円(税抜)〜で容量最大120GB!しかも安いだけじゃなく
大人気WordPressの簡単インストール/ウェブメーラーなど
機能も満載!共有/独自SSLもバッチリ対応でセキュリティ対策も万全!
もちろん、オンラインマニュアルやライブチャットなど、
充実したサポートで初心者の方でも安心です。
無料のお試し期間が10日間ありますので、
まずはお気軽にご利用してみてくださいね!
▼ロリポップ!レンタルサーバーはこちら
お名前.com レンタルサーバー