yasudacloudの日記

札幌に住むソフトウェアエンジニア

PHPでUNIXドメインソケットの3種類を書く

積読消化中、「Goならわかるシステムプログラミング」を読んでいたらUNIXドメインソケットについて気になった記述がありました。

ファイルパスを指定する以外の作成方法もあります。ただし、Go言語からは使えません。

これまでphp-fpmやMySQLでファイルパス有り(*.sockファイル)のパターンしか扱ったことなかったので一度触れておきたい所です。

ネットでぐぐるとUNIXドメインソケットには以下の3つの種類(接続方式?)があることが分かったのでそれぞれ実装していきます。ネット記事ではCやPythonのコードが散見されたので、被らないようにPHP8で書いてみました。

 

ファイルパス

まずよくある*.sockを使うパターン。tcpとudpのサンプルは以下URLにありますが、unixのコードは見当たりませんでした。仕様はドキュメントそのままって感じなのでコードの記載くらいにします。

PHP: stream_socket_server - Manual

gist.github.com

gist.github.com

無名

こちらは以下にコード例の記載がありました。socketpairを使ってフォークした親子間のプロセスで通信するような実装に見えますが、コード眺めるだけだと動きが分かりにくかったので少し手を入れました。1つのソフトウェア上で完結し、外部から連携させたくない場合に有用かも?

PHP: stream_socket_pair - Manual

gist.github.com

抽象 名前空間

php.netの日本語/英語を見ても抽象名前空間に関する記述が見当たらず。

gist.github.com

 

gist.github.com

抽象名前空間(abstractと表現される模様)の仕様的にはファイルパスのパスの先頭をnullバイト(PHPのエスケープ文字で言うと\0)から始める文字列にするだけで、ファイルパスと変わらんのでは? くらいに思ってたのですがちょっと苦戦しました。

 

ハマったところ

PHP Fatal error:  Uncaught Exception: Failed Socket Server in

このエラーがなかなか解決できず時間がかかりました。"unix://\0testtest"の指定が悪いのかなと色々直してもダメで、PHPのコードを読みにいくとLinux-only という単語をみっけてしまいました。MacOSでは駄目なんですね😅

github.com

 

Linux(Docker)でリトライ

前述のコードがあるソースのルートで下記を実行します。composerとかも使ってなく、ホスト側のコードをそのままマウントして実行して問題ないです。

docker pull php:8.1.9
docker run -it --name php8 -v "$PWD":/app php:8.1.9 bash
docker-php-ext-install sockets pcntl
cd /app

コンテナ内で再度 php_unix_domain_socket_abstract_server.phpとphp_unix_domain_socket_abstract_client.phpを実行したらうまく動作しました。

 

各*_server.phpをnetstatで確認

コンテナ内でnet-toolsのインストールコマンド

apt install net-tools

ファイルパスのnetstat -a

Proto RefCnt Flags       Type       State         I-Node   Path

unix  2      [ ACC ]     STREAM     LISTENING     27408    test.sock

 

無名のnestat -a

Proto RefCnt Flags       Type       State         I-Node   Path

unix  3      [ ]         STREAM     CONNECTED     33176    

unix  3      [ ]         STREAM     CONNECTED     33175    

 

抽象名前空間のnetstat -a

Proto RefCnt Flags       Type       State         I-Node   Path

unix  2      [ ACC ]     STREAM     LISTENING     28363    @testtest

 

まとめ

異なるソフトウェア間(php-fpmとNginx間やRedis-各プログラミング言語間など)ではファイルパスが分かりやすくて良いですが、無名は他の実装方法の方が有力なケースが多い気がしていて使い所があまりピンときていません。。

数年前に出たものですが、「Linuxシステムコール基本リファレンス」(これも積読)を読んでから「Goならわかるシステムプログラミング」を読むと効率的に学習できそうです。今回の3種類については特に記載されてませんでしたけど。

低レイヤーはまだまだ知らないことが多く、勉強不足です(-.-;)y-~~~