2011-09-13 10 views
29

私はLinux用のUnixドメインソケットサーバーを作成しています。プロセスがUnixドメインソケットにバインドされているかどうかを知るには?

Unixドメインソケットの特色私はすぐにリスニングUnixソケットを作成すると、一致するファイルシステムエントリが作成され、ソケットを閉じることでそれを削除しないことが分かりました。さらに、手動でファイルシステムのエントリを削除するまでは、bind()は、bind()のパスがファイルシステムに既に存在する場合にはEADDRINUSEで失敗します。

したがって、サーバの再起動時にEADDRINUSEが発生しないように、ソケットのファイルシステムエントリをサーバシャットダウン時にunlink()にする必要があります。ただし、これはいつでも行うことはできません(サーバークラッシュなど)。ほとんどのFAQ、フォーラムの投稿、Q &私が見つけたウェブサイトは、対応策としてbind()を呼び出す前にunlink()ソケットにのみ助言してください。しかし、この場合、プロセスがこのソケットにバインドされているかどうかを知ることが望ましくなり、それがunlink()の前に行われます。

実際には、プロセスが依然としてバインドされている間にUnixソケットを作成してから、リスニングソケットを再作成してもエラーは発生しません。しかし、その結果、古いサーバープロセスはまだ実行されていますが、到達不能です。古いリスニングソケットは新しいソケットによって「マスク」されます。この動作は避けなければなりません。

理想的には、Unixドメインソケットを使用すると、ソケットAPIは、TCPソケットまたはUDPソケットをバインドする際に公開される「相互排除」と同じ動作を提供する必要があります。 "ソケットSをアドレスAにバインドしたい、プロセスが "残念ながら、これはそうではありません...

この「相互排除」の動作を強制する方法はありますか?いいえ、このアドレスにバインドしてください。または、ファイルシステムのパスを指定すると、からソケットAPIを介して、システム上のプロセスにこのパスにバインドされたUnixドメインソケットがあるかどうかを知る方法がありますか?ソケットAPI(flock()、...)の外部に同期プリミティブを使用する必要がありますか?または私は何かを逃していますか?

ご意見ありがとうございます。

注:Linuxの抽象名前空間unlink()へのファイルシステムのエントリがないため、UNIXソケットはこの問題を解決するようです。しかし、私が書いているサーバーは、一般的なものを目指しています。リスンアドレスを選択する責任はないので、両方の種類のUnixドメインソケットに対して堅牢でなければなりません。

答えて

18

私はパーティーに非常に遅く、これはずっと前に答え​​られたことを知っていますが、私はこの何か他のものを探す際に遭遇しました。

bind()からEADDRINUSEが返ってきたら、ソケットに接続するエラーチェックルーチンを入力できます。接続が成功すると、実行中のプロセスが少なくとも生きていて、accept()を実行できます。これは私があなたが達成したいものを達成するための最も簡単でポータブルな方法であると私に思います。これは、実際にはまだ実行されているが、「スタック」何とかしてaccept()を行うことができないので、この解決策は確かにばかプルーフをされていないことがあり、最初の場所にUDSを作成し、そのサーバーでの欠点を有しているが、それは一歩です私は思う。

connect()が失敗した場合は、エンドポイントunlink()に進み、もう一度bind()を試してください。

9

私はあなたがすでに考慮したことを超えて行われるべきではないと思います。あなたはそれをよく研究したようです。

ソケットがunixソケットにバインドされているかどうかを判断する方法はありますが(明らかにlsofとnetstatで行います)、複雑でシステムにも依存していますので、 。

実際には、他のアプリケーションとの名前の衝突や、自分のアプリの以前のインスタンスを扱うという2つの問題が発生しています。

定義上、複数のインスタンスを同じパスにバインドしようとするべきではないため、一度に1つのインスタンスだけを実行することを意味します。その場合、標準のpidファイルロック手法を使用するだけで、2つのインスタンスが同時に実行されることはありません。既存のソケットのリンクを解除したり、ロックを取得できない場合でも実行したりするべきではありません。これにより、サーバクラッシュのシナリオも処理されます。ロックを取得できる場合は、バインドする前に既存のソケットパスのリンクを解除できることがわかります。

AFAIKを使用して、衝突を引き起こす他のプログラムを制御することはあまりありません。ファイルのパーミッションは完全ではありませんが、オプションが利用可能な場合は、独自のユーザ/グループにアプリを置くことができます。既存のソケットパスがあり、そのパスを所有していない場合は、リンクを解除してエラーメッセージを出して、ユーザーまたはsysadminがそれを並べ替えるようにしてください。設定ファイルを使用して簡単に変更可能にしたり、クライアントが利用できるようにすると、動作する可能性があります。それを超えては、これは本当に重要なアプリケーションでない限り、大規模な過度の攻撃のように見える、何らかの発見サービスをほとんど実行しなければなりません。全体的に

あなたは、これが実際に頻繁に起こらないことをいくつかの快適さを取ることができます。

+0

あなたの答えをありがとう。従来のロックファイルシステムを使用することは、最も安全な方法です。また、サービスディスカバリシステムが過不足であるかどうかに関しては、皮肉なことに、このサーバはサービスディスカバリシステムの一部であることが計画されています(サービスの「登録」システムが適切でしょう)。これはあなたの質問に答える必要があります;-) –

関連する問題