コグノスケ


2022年 10月 2日

ニコニコ動画の動画は 2種類ある

だいぶ周回遅れですが、リコリス・リコイルの最終回を見てました。最終回に限らず銃撃アクションはどの回も良かったな〜と思います。設定はイマイチ良くわからないですけど、あまり気にしても仕方ないです。それはさておき。ニコニコ動画は、

  • 無料版: 期間限定公開
  • 有料版(d アニメ支店)

があって、有料版はちょっと変わってるらしいので、試しに契約してみました。サブスクリプション方式でした、月額 440円だそうです。

ニコニコ動画の動画配信方式の概要

現在のニコニコ動画の配信方式は HLS(HTTP Live Streaming, 規格は RFC8216 にて規定)といいまして、MPEG2-TS ファイルを細かく(3〜10秒程度)分割して、クライアントから再生要求された位置から順に送るだけのシンプルな方式です。MPEG2-TS の弱点はインデックスなどの情報が一切なくてサーチが大変なことですが、あらかじめ分割しているため苦労してサーチをする必要がありません。

ちなみにリコリス・リコイルの無料放送版の場合、コーデックは見ての通りで Full HD じゃないです……。有料版でも HD 720p ですから、画質が気になる方にはイマイチかもしれません。他のアニメも同じなのでしょうか?調べていないのでわかりませんけど。

  • 動画: H.264 HD (1280x720)
  • 音声: AAC 48kHz

HLS では *.m3u8 というプレイリストも一緒に送られてきて、そこに TS ファイル名が全て載っています。プレイリストにある TS を順番にダウンロードし、単純連結するだけで動画全体の TS ファイルが引っこ抜けます。これはセキュリティホールとかではなく元々 HLS はこういう仕様です。

無料版と有料版の配信方式はちょっと違う

有料版も同様に HLS で配信されていますが AES-128-CBC 暗号化されていて、TS ファイルを引っこ抜いても再生できません。しかしなぜか無料版は暗号化されておらず TS ファイルを引っこ抜くと再生できてしまいます。設定ミス……?わざと?まあどっちでもいいですけど。


無料放送版に入っているニコニコ動画の透かし

キャプチャだとわかりにくいかもしれませんが、右下に「ニコニコ」という透かしが入っています。有料版は入っていません。

無料版と有料版は動画も違う

TS ファイルのサイズを比較(AES-128-CBC 暗号化でファイルサイズは変化しないので、この比較には意味がある)してみましょうか。使ったのはリコリス・リコイル最終話です。

  • 無料版: 377MB
  • 有料版: 296MB

有料版(d アニメ支店版)は 100MB くらい小さいです。無料版は先ほど説明したように右下に透かしを入れるために再エンコードしていると思いますが、再エンコードだけでは説明できないほどサイズが違います。なんで?と思って調べてみたら、どうやら、

  • 無料版: 30fps
  • 有料版: 24fps

になっているようです。オープニングのエレベータが降りていくシーンが非常にわかりやすいです。高速(120fps とか)で動画が撮れるカメラを使うと、無料版は 5コマに 1回、画が止まることがわかります。

有料版(24fps)が
1 2 3 4 5 6 7 8
という出方だとして、無料版(30fps)は
1 2 3 4 4 5 6 7 8 8
みたいな出方をします。

意図通りか間違えたか知りませんが、無料版だけ 30fpsに変換しているためファイルサイズがやたらデカいようです。暗号化もされていませんし、どちらかというと無料版の方が不思議な作りですね。

メモ: 技術系の話は Facebook から転記しておくことにした。色々と加筆修正。

編集者: すずき(更新: 2022年 10月 11日 02:49)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 3日

ニコニコ動画の無料版がカクついている理由

ニコニコ動画の 24p → 30p の変換の仕方と、テレビなどが行っている 24p → 60i の変換の仕方(2-3 プルダウン、3-2 プルダウンとも呼ぶ)を図示してみました。もうちょっとわかりやすくしたかったけど……絵心が足りませんでした。


24p から 30p, 60i(2-3 プルダウン), 60p への変換

24p → 30p 変換は非常にシンプルで、24p フレームの表示すべき時間(PTS: Presentation Timestamp)に到達していたら表示、まだだったら前と同じフレームをリピート、という非常に単純な処理です。利点は画が自然なことで、欠点はカクつくことです。縦や横に一定速度でスクロールするシーンは進んで止まってを繰り返すためガクガクします。

2-3 プルダウンは若干ややこしく、インターレース(偶数ラインと奇数ラインが交互に更新される)の特徴を使います。60i の 3コマ目(5-6 フィールド)に 24p の 2, 3 コマ目の偶数、奇数ラインを混合した画を出します。4コマ目(7-8 フィールド)は 24p の 3, 4 コマ目の混合です。利点はカクつきが少ないことで、欠点は画が不自然になることです。例えば 24p の 2 コマ目にリンゴ、3コマ目に突然オレンジが映る場合、60i の 3コマ目はリンゴとオレンジが縞々に合わさったキメラ画像になります。

このように 2-3 プルダウンは良くできているものの完全無欠ではないので、テレビによって扱われ方が違います。最近のテレビであればおそらく画像が 24p だと検知すると自動的に 2-3 プルダウンが発動すると思いますけど、製品によっては「映画モード」とかに変えないと発動しないかもしれません……。

最後に 24p → 60p 変換ですが、何の工夫もないのにほぼカクつきなしで不自然な画もありません。24p は下手に 30p とか 60i に変換せず、60p で殴りなさいという悲しい結論ですね。細かく見れば 2コマ、3コマ、2コマ、3コマ……と繰り返されるので 1/120 秒の揺らぎがあります。でも人間にはわからないと思います。たぶん。とりあえず私はさっぱりわかりません。

メモ: 技術系の話は Facebook から転記しておくことにした。色々とマージ&加筆修正。

編集者: すずき(更新: 2022年 10月 5日 18:46)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 4日

ニコニコ動画の暗号化 HLS の謎

興味本位で調べていたんですが、ニコニコ動画の HLS の暗号化の仕組みがわかりました。基本的には暗号化 HLS と同じです。m3u8 ファイルに EXT-X-KEY Tag(仕様は RFC8216 4.3.2.4 EXT-X-KEY にあります)があって、METHOD=AES-128(暗号化方式が aes-128-cbc 方式)、鍵のありかを示す URI、IV(Initial Vector)が書いてあるタイプです。他の Attributes は使っていません。

暗号化自体は aes-128-cbc ですが、復号用の鍵の扱いは HLS の規格と異なっており URI に示されたファイルを使っても復号できません。暗号化の仕組みを見た限り、コスト度外視でガチガチにガードする DRM というより、ffmpeg などの HLS 再生に対応した有名ツールを使ってお手軽ダウンロードされなければヨシ!という作りに見えます。HLS 規格から大改造すればするほど既存ライブラリが使えなくなったり、クライアントもサーバーも作るのが大変になるからではないかと推測しています。

AES は鍵さえわからなくすれば復号できませんから、基本的には HLS に準拠して扱いを楽にしておき、鍵だけ規格から外した扱いで実装してある、なかなか面白いバランスでした。商用サービスの設計を垣間見た気がします。なるほどなあ。

DRM 解除してはいけません

鍵の取得方法も調べましたが詳しくは述べません。RC2 から(※)のニコ動ユーザーとして、これからも末永く利用したいので、ニコ動の不利益になることは本意じゃないです。ニコ動がんばって。応援してるぜー。

改正著作権法では DRM 回避行為そのものも違法(今は罰則はありませんが……)です。回避装置の譲渡には懲役刑や罰金刑といった刑事罰があります(参考: 私的リッピングも違法!?いよいよ改正著作権法が一部施行 - 週刊アスキー)。

「再現可能なレベルの回避手段の解説」=「回避装置の譲渡(懲役刑や罰金刑といった刑事罰がある)」とみなされて当然だと思うので、私は絶対に DRM 解除方法は公には書きません(方法を知っても他人に教えません)。皆様もパズルの答えの感覚で「DRM の解き方がわかった!方法はこうしてこう!」ってその辺に書かないようにしましょう。

(※)ニコニコ動画の変遷を見ると RC2 は 2007年〜2008年頃だから約 15年経ちましたか。早いもんですね。

編集者: すずき(更新: 2022年 10月 11日 03:41)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 10日

Microsoft Edge の特別な機能

Microsoft Edge は独自の HTML レンダリングエンジンを捨てて、Google Chrome と同様 Blink という HTML レンダリングエンジンに切り替えました(2020 年くらい)。という経緯を知っていたので、今まで Edge と Chrome は大差ないと思っていたのですが、Alt+Tab を押したときの挙動が違うことに気づきました。


Windows 10 は Alt+Tab で Edge のタブ切り替えができる

Edge のウインドウは 1つしかありませんが、Alt+Tab を押すと Edge が 2つ表示され、Edge のタブが Windows のウインドウのように特別扱いされることがわかります。普段 Edge を使わないため全くこの機能を知りませんでした。また Windows 10 の設定ウインドウを見ていて、この機能を OFF にできることも知りました。


Edge のタブを特別扱いする機能は ON/OFF できる

Edge 以外のブラウザ、ファイル管理、ターミナルなど、タブ機能を持ったアプリはそこそこ多いと思いますが、Edge のタブだけ Alt+Tab で切り替え、他のタブ機能は切り替えできない、という一貫性のなさは混乱しますが……。ウケが良かったらそのうち OS の標準機能になるかもしれませんね。

編集者: すずき(更新: 2022年 10月 11日 11:51)

コメント一覧

  • hdk 
    いつ頃だったかのMicrosoft Officeも、MDIなのに、子ウインドウがタスク バーに並ぶという謎な設定がデフォルトだったのを思い出しました。Office 97の頃は、タイトル バーのグラデーションがなかったWindows 95でも独自でグラデーションをつけていましたし、Internet Explorerのシェル統合なんていうのもありましたし、Microsoftは自社製品で変なことするのが好きですよね。 
    (2022年10月11日 20:31:01)
  • すずき 
    ああー、懐かしいですね。いきなりWindowsを変えると騒ぎになるから、Officeとかで部分的にGUIを変えてみて、ユーザーの反応を見ているんじゃないかなあと推測してます。 
    (2022年10月12日 00:51:11)
open/close この記事にコメントする



2022年 10月 11日

長物エアガン一号機ドラグノフ

目次: 射的 - まとめリンク

保存場所がないのでエアガンはハンドガンしか買わないようにしていたのですが、頑張れば 1つくらいなら置けるか?ってことで 1つだけ買いました。

台湾の WE-Tech 製、SVD ことドラグノフ狙撃銃です。ロシア語は良くわかりませんが、S がスナイパー、V がライフル、D がドラグノフに相当するみたい。英語(Dragunov Sniper Rifle)とは逆順ですね。


WE-Tech SVD

シンプルかつ細身のフォルムがカッコいいです。形だけで言えば一番好きなのは H&K PSG-1 ですが、スコープがなくても撃てる方が都合が良かったので、次くらいにカッコいいと思う SVD 先生を選びました。

黒いプラスチックのストックより、木というかフェイクウッドのストックにするとさらにソビエト感が出るんですけど、値段見たらすっごい高かったのでヒヨってやめました……。

めっちゃ良い音がする

BB 弾を発射すると、銀色のボルト(アルミ製かな?)のところがガス圧で後退&前進します。大きく重いボルトなだけあって、ガシーン!という強めの衝撃、良い金属音が鳴ります。おおーこれはなかなか良いです。家だと相当ウルサイのが難点ですが……。

ボルト以外の部分も基本的に金属らしき部品が多いです。鉄とアルミ製かな?これも重量感があって良いですね。

取り回しは良くない(当たり前)

家に箱が届いた瞬間に「何だ?デケェな!」って思いましたが、箱を開けてもやっぱりデカいです。約 120cm あります。狙撃銃は最長の部類ですから当たり前ですね。1つ目に買う銃じゃありませんでしたか……?まあ、カッコ良ければ全てヨシ!ヨシ!!

家で試し打ちしましたが、銃身が長すぎて BB 弾が飛ぶ方向が良く見えません。サイトをどこに合わせたら良いかわからなくて困ったので、レンジで試し打ちしながら調整した方が良いかもしれません。今度頑張って背負って行きましょうか。

あとは WE-Tech に限らず海外製ガスガンではあるある現象らしいですが、

  • ガスが入ったかどうかわからない(バルブを吹き戻しあり仕様に交換すると良いそうな)
  • ガスの減りがすごい早い(海外ガスガンはリコイルスプリングが硬いらしく、スプリング交換した方が良いそうな)
  • BB 弾がめっちゃ入れにくい

BB 弾は未だにコツが良くわからないです。失敗してパカーーンってぶちまけてしまい地味にイライラします……。

編集者: すずき(更新: 2022年 10月 16日 16:20)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 16日

ベレッタ 92 のグリップを交換

目次: 射的 - まとめリンク

東京マルイ製の U.S.M9 や M9A1 といったベレッタ 92 を基にしたエアガンは非常に良くできているのですが、イタリアのベレッタ社とのライセンスの関係上?ベレッタ社のロゴが使えないようです。エアガンのグリップには似た形のニセのロゴが描かれています。

ちなみにベレッタ社は純正のプラグリップを販売しています。銃本体ではないので日本に持ち込んでも問題はないし、思っていたより安かった(4,000円くらい)ので試しに買いました。

届いた品物を見たところ、面白いことにベレッタ純正のプラグリップの方が安っぽく、東京マルイ製のニセ物ロゴグリップの方が明らかに質が良いです。


ベレッタ 92 のグリップ、左: ベレッタ純正、右: 東京マルイ製

左がベレッタ純正、右が東京マルイ製です。東京マルイ製の方がグリップの山が均一で見た目もきれい、つや消しもぬかりなくて、手触りもよいです……。可能ならロゴだけ移植したいくらいの出来です。

今回のグリップ交換は見た目改善だけですが、副次的な効果として銃が軽くなります。なぜかというと東京マルイのグリップ内には重りが入っていて、ベレッタ純正のグリップでは重りが入っていないためです。エアガンの銃本体は実銃と異なりプラスチック製で軽いため、グリップを重くして実銃らしさを出そうとしています。なのでマルイ→ベレッタグリップに交換するとグリップ内の重りのぶんだけ軽くなってしまうのです。

実銃用のグリップのはず

届いた商品の箱を開けると、各トイガンメーカーのベレッタ 92 タイプのエアガンに対して、そのまま付くか付かないか(=多少の加工が必要)を説明した紙が入っていました。


検索用に文字起こししておきました。

★★東京マルイ ガス BLK★★
M9A1
取り付け可能です。

M92F ミリタリー
右側のグリップスクリューナットの位置とグリップがずれているので、グリップ部の穴を広げ、トリガーバーの可動部のすり合わせを行えば取り付け可能です。

タクティカルマスター
スライドストップがロングタイプの為、取付不可。それ以外は M92F ミリタリーと同様です。

★★KSC ガス BLK★★
M9 シリーズ
両側のグリップスクリューナットの位置がグリップがずれている為、穴を広げる調整が必要です。

★★マルシン モデルガン★★
M92F シリーズ
取り付け可能です。

★★タナカ モデルガン★★
M92F シリーズ
両側のグリップスクリューナットの位置がグリップがずれている為、穴を広げる調整が必要です。

(注意書きの部分)
当社製品はエアソフトガンの分解・修理・調整に熟知された方を対象としております。
銃本体とグリップにも個体差があり必ずしもフィットするとは限らないのでご注意ください。
誤使用及び、経験不足/加工による破損等の諸問題が発生した場合いかなる状況でも保証はいたしかねます。

実銃用のグリップを日本で売る=エアガンに装着するしかない、ということはベレッタ社もわかっているようですね。

編集者: すずき(更新: 2022年 10月 21日 12:27)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 19日

蛍光灯を交換した

おそらく 10年前くらいに買ったシーリングライトの蛍光灯が切れてしまいました。交換用の蛍光灯を検索したところ既に廃番で、2世代ほど世代交代していました。蛍光灯は長持ちですねえ。

  • FHD85ECWH(2007年10月01日〜2016年06月30日)
  • FHD85ECWL(2016年06月01日〜2022年09月30日)
  • FHD85ECWLF3(2022年10月01日〜)

今日買ったユーザーが次買うのは 3世代先の製品だと考えると、開発は難しいですね。安易に口金の形を変えたりすると「交換しようとしたが嵌らないよ(泣」というクレームの嵐になりそうですし。設計に失敗したら新型で置き換えるまで尋常じゃない時間掛かります。

要らないお世話ですけど、たった数千円なのにこんな低い交換頻度で儲かるんだろうか?とも思います。2回目交換する前にシーリングライト本体が壊れそうですよね。

編集者: すずき(更新: 2022年 11月 12日 15:49)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 20日

医療保険の給付金

医療保険の給付金が無事給付されました。給付金は、入院一時金 + (入院日数 9日扱い x 日ごとの給付) = 合計 10万円くらいでした。

給付金の申請をしたのは久しぶりだったため、給付申請に添付する書類をミスって 2回くらい返ってきました。住友生命にはお手数をお掛けをしました。ま、最終的に給付されたので良いでしょう……。

不幸中のハピネス

私と奥さんが COVID-19 に感染したのは 8月です。8月は COVID-19 の自宅療養=入院扱い、となる時期としてはほぼ最後(10月から入院扱いではなくなった)でした。COVID-19 に感染したのは不幸でしたが、医療保険の給付にギリギリ滑り込めたことは不幸中の幸いと言えるでしょう。

最近 COVID-19 に感染する人が急増し、生保各社が給付金支払いを渋り始めました。住友生命、日本生命は 10月から医療保険の給付対象から自宅療養を外しています。他社も恐らく同様でしょう。

9月だろうが 10月だろうが COVID-19 の自宅療養が必要なことに変わりはないのに、生命保険会社から給付金支払いが増えて嫌です、もう払いませんなんて梯子外しをされるとは思いませんでしたね……。

改めて生命・医療保険の契約内容を眺めましたが、加入している意味が薄れてきていますね。夫婦共働きで子供もいないので生命保険はもう不要でしょう。医療保険だけなら共済保険などの方が良いですし。じゃあ今すぐ解約だ!というほどの負担ではないですけどね……少なくとも 5年後の契約更新をしないのは確実です。掛け金がさらに倍になるのでさすがに高すぎます。

編集者: すずき(更新: 2022年 10月 29日 05:04)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 25日

雑誌に記事が掲載された

IT 系の職業に就いている人であれば、恐らく一度は目にしたことがある Interface という雑誌があります。今回 12月号に記事を寄稿しました。記事の見本は 2022年 12月号 - Interface - CQ 出版から見ることができます。

会社と出版社にご縁があったそうで、春頃から不定期連載が始まりました。特に会社の製品の宣伝はせず、RISC-V CPU 開発に関してハードウェアからソフトウェアまで広く易しく扱う内容となっています。連載は全 10回の予定、執筆者は会社の技術者で分担しており 1人 1記事ずつ担当しています。たぶん。

連載はちょうど真ん中で 5回目となります。記事の内容は RISC-V のツールチェーンの入門編で 4ページほどの短い記事です。記事の内容はここでは公開できない(しばらく時間が経ったら OK らしいです)ので、もし気になるようでしたら雑誌をご覧くださいませ。

編集者: すずき(更新: 2022年 10月 29日 01:59)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 29日

ヘッドフォン

今までお世話になった(なっている)ヘッドフォンたちをまとめておきます。

密閉タイプ。

SONY MDR-XD050
音は良いです、ややドンシャリかな?耳当てはフワフワで良いですが、すぐ表面が剥がれてしまうのはイケてないです。
SHURE SRH440-A
音はとても良いです。耳当ての合皮が汗を全く吸わず、夏はイマイチでした……。
SONY MDR-HW700
無線タイプです。音は良いのですが、無線と Wi-Fi と干渉するのがあまり好きではないです。高かったのにあまり使ってなくてもったいない。

オープンタイプ。

Pioneer SE-M290
音はモワモワで遠くに居る感じであまり良くはないですが、付け心地はとても良くて疲れません。
audio-technica ATH-TAD500
音はややキンキンですが私は好きな音です。長時間使うと耳が痛いのが難点です。ヘッドバンド部分が壊れてしまったのでお別れ。
Superlux HD681B
金属っぽいキンキンした音です。耳当てがなんだかゴワゴワしていてイマイチです。
SENNHEISER HD599
癖を感じない良い音です。耳当ては良い感じですが、サイズが合っていないのか長時間使うと頭痛がします。
編集者: すずき(更新: 2022年 11月 12日 15:31)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年 10月 31日

Kill できる popen が欲しい

会社で popen で作った子プロセスが残ってしまうが何とかならないか?という相談を受けて、面白そうだったので取り組んでみました。日記でも残しておきます。コード的には特に機密情報はありません。

popen て何ですか

マニュアルを読みましょう(Manpage of popen)。少しだけ解説するなら、子プロセスの入出力をパイプ経由で送ったり受け取ったりできるライブラリ関数です。

例えば yes コマンドを popen で実行すると、出力パイプからは y y y y ... という文字列が読みだせます。

popen の困ったところ

非常に便利な popen ですが、子プロセスが終了するかどうかは子プロセス次第、言い換えれば子プロセスを強制的に終了させる方法がないことが欠点です。

例えば、先ほど挙げた yes コマンドは勝手に終了しないコマンドの代表例です。popen 関数を呼んだ親プロセスが終了しても、子プロセスの yes コマンドは終了しないまま残ります。

改良 popen を作る

実は popen 関数は既存のライブラリ関数やシステムコールの組み合わせで実現できます。先にコードを載せましょうか。

kill できる popen のコード

/* SPDX-License-Identifier: Apache-2.0 */

#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void usage(int argc, char *argv[])
{
	printf("usage:\n"
		"  %s cmdline\n", argv[0]);
}

int main(int argc, char *argv[])
{
	const char *cmdline;
	pid_t pid, pgrp;
	int pipefd[2];
	FILE *fp;
	int r;

	if (argc <= 1) {
		usage(argc, argv);
		return -1;
	}
	
	cmdline = argv[1];
	
	printf("cmdline: %s\n", cmdline);

	// パイプを作成します。パイプに読み書きするファイルディスクリプタ(pipefd)2つが返されます。
	// pipefd[0] が読み出し用、pipefd[1] が書き込み用です。
	r = pipe2(pipefd, 0);
	if (r == -1) {
		perror("pipe2");
		return -1;
	}

	// ファイルディスクリプタを FILE * でラップします。
	// popen は FILE * を返すインタフェースなので、それに合わせるためです。
	fp = fdopen(pipefd[0], "r");
	if (fp == NULL) {
		perror("fdopen");
		return -1;
	}

	// 子プロセスを生成します。
	//    pid には子プロセスの場合は 0、親プロセスの場合は子プロセスのプロセス ID が返されます。
	pid = fork();
	if (pid == -1) {
		perror("fork");
		return -1;
	} else if (pid == 0) {
		// child

		// 子プロセスを新たなプロセスグループに移します。
		// 理由はあとで kill を呼ぶときに親プロセスまで巻き添えにしないようにするためです。
		// setpgid を呼ばない場合
		//    プロセスグループ A: 親、子、指定したコマンド
		//    kill(プロセスグループ A): 親も子もコマンドも全て強制終了してしまう
		// setpgid を呼んだ場合
		//    プロセスグループ A: 親
		//    プロセスグループ B: 子、指定したコマンド
		//    kill(プロセスグループ B): 子とコマンドのみ強制終了
		r = setpgid(0, getpid());
		if (r == -1) {
			perror("setpgrp");
			return -1;
		}

		// 子プロセスの標準出力を閉じ、パイプの書き込み用ファイルディスクリプタを代わりに使います。
		// つまり子プロセスの出力がパイプに書き込まれます。
		r = dup2(pipefd[1], 1);
		if (r == -1) {
			perror("dup(child)");
			return -1;
		}

		// シェルを利用して引数に指定されたコマンドを実行します。
		// シェルを利用する理由は popen と同じ仕様(コマンド引数を 1つの文字列で渡す)にしたいからです。
		// シェルを挟まない場合は、複数の文字列に分割して渡す必要があります。
		r = execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL);
		if (r == -1) {
			perror("execl(child)");
			return -1;
		}

		// not reache here
		return -1;
	}

	// parent

	// パイプから読みだすと子プロセスが標準出力に出そうとした文字列が読める
	char buf[10];
	memset(buf, 0, sizeof(buf));
	fread(buf, 1, sizeof(buf) - 1, fp);

	printf("read from pipe: %s\n", buf);

	printf("sleep 5\n");
	sleep(5);

	// 子プロセスのプロセスグループを取得します。
	//    pid には子プロセスのプロセス ID が返されます。
	//    fork の部分も参照してください。
	printf("getpgid() pid:%d\n", (int)pid);
	pgrp = getpgid(pid);
	if (pgrp == -1) {
		perror("getpgid");
		return -1;
	}

	// 子プロセスのプロセスグループを強制終了します。
	printf("kill(SIGTERM) pgrp:%d\n", (int)pgrp);
	r = kill(-pgrp, SIGTERM);
	if (r == -1) {
		perror("killpg");
		return -1;
	}

	// 子プロセスが終了するまで待ちます。
	printf("wait child pid:%d\n", (int)pid);
	int wstat;
	r = waitpid(-pid, &wstat, 0);
	if (r == -1) {
		perror("waitpid");
		return -1;
	}
	if (r != pid) {
		fprintf(stderr, "kill %d but terminated pid %d, why?\n", (int)pid, (int)r);
	}

	printf("done!!\n");

	return 0;
}

そこそこ長いですね。

簡単な解説

コードを見ると目がチカチカする方向けにコメントだけ抜き出しました。動きが分かりやすいと思います。

  • pipe2: パイプを作成します。パイプに読み書きするファイルディスクリプタ(pipefd)2つが返されます。pipefd[0] が読み出し用、pipefd[1] が書き込み用です。
  • fdopen: ファイルディスクリプタを FILE * でラップします。popen は FILE * を返すインタフェースなので、それに合わせるためです。
  • fork: 子プロセスを生成します。

子プロセスはこんな動きです。

  • setpgid: 子プロセスを新たなプロセスグループに移します。理由はあとで kill を呼ぶときに親プロセスまで巻き添えにしないようにするためです。
  • dup2: 子プロセスの標準出力を閉じ、パイプの書き込み用ファイルディスクリプタを代わりに使います。つまり子プロセスの出力がパイプに書き込まれます。
  • execl: シェルを利用して引数に指定されたコマンドを実行します。シェルを利用する理由は popen と同じ仕様(コマンド引数を 1つの文字列で渡す)にしたいからです。シェルを挟まない場合は、複数の文字列に分割して渡す必要があります。

親プロセスはこんな動きです。

  • getpgid: 子プロセスのプロセスグループを取得します。
  • kill: 子プロセスのプロセスグループを強制終了します。
  • waitpid: 子プロセスが終了するまで待ちます。

プロセスの親子関係はこうなります。

プロセスの親子関係
|-a.out,536208 yes
|   `-sh,536209 -c yes
|       `-yes,536210

もしコマンドがさらに孫、ひ孫プロセスを生成しても、プロセスグループが一緒である限り kill が効くはずです。

残っている改善点

今回紹介した実装は popen の完全な上位互換ではありません。理由としては入力側を扱えないこと、popen のような API として使えないこと、が挙げられますが、拡張は容易だと思います。

編集者: すずき(更新: 2022年 11月 8日 14:41)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報