40

Linux用のUnixドメインソケットサーバーを書いています。

私がすぐに気付いたUnixドメインソケットの特徴は、リスニングUnixソケットを作成すると、一致するファイルシステムエントリが作成されますが、ソケットを閉じても削除されないことです。さらに、ファイルシステムエントリが手動で削除されるbind()まで、同じパスに再度ソケットすることはできません。指定されたパスがファイルシステムにすでに存在する場合はbind()失敗します。EADDRINUSE

結果として、サーバーの再起動unlink()を回避するために、サーバーのシャットダウン時にソケットのファイルシステムエントリを'edする必要がありEADDRINUSEます。ただし、これは常に実行できるとは限りません(つまり、サーバーのクラッシュ)。私が見つけたほとんどのFAQ、フォーラムの投稿、Q&A Webサイトは、回避策として、unlink()を呼び出す前にソケットにアドバイスするだけbind()です。ただし、この場合、プロセスを実行する前に、プロセスがこのソケットにバインドされているかどうかを知ることが望ましくなりますunlink()

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

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

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

あなたの提案をありがとう。

注:Linuxの抽象名前空間Unixソケットは、へのファイルシステムエントリがないため、この問題を解決しているようですunlink()。ただし、私が作成しているサーバーは汎用を目的としています。リスニングアドレスの選択については責任を負わないため、両方のタイプのUnixドメインソケットに対して堅牢である必要があります。

4

2 に答える 2

25

私はパーティーに非常に遅れていることを知っています、そしてこれはずっと前に答え​​られました、しかし私はちょうどこれが何か他のものを探しているのに遭遇しました、そして私は別の提案をします。

EADDRINUSEからの復帰に遭遇したときbind()、ソケットに接続するエラーチェックルーチンに入ることができます。接続が成功した場合、実行中のプロセスが少なくとも十分に機能しているため、を実行できますaccept()。これは、あなたが達成したいことを達成するための最も簡単で最もポータブルな方法であると私は思います。そもそもUDSを作成したサーバーは実際にはまだ実行されているが、何らかの理由で「スタック」して実行できないという欠点がありますaccept()。したがって、このソリューションは確実に確実ではありませんが、正しいステップです。方向性だと思います。

失敗した場合は、エンドポイントconnect()に進んで再試行してください。unlink()bind()

于 2012-12-05T09:25:33.120 に答える
11

あなたがすでに考えたこと以外にやるべきことはあまりないと思います。あなたはそれをよく研究したようです。

ソケットがUNIXソケットにバインドされているかどうかを判断する方法はありますが(明らかにlsofとnetstatがバインドしています)、複雑でシステムに依存しているため、発生した問題に対処する価値があるかどうか疑問に思います。

あなたは本当に2つの問題を提起しています-他のアプリケーションとの名前の衝突の処理とあなた自身のアプリの以前のインスタンスの処理です。

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

衝突を引き起こす他のプログラムを制御するためにAFAIKを実行できることはあまりありません。ファイルのアクセス許可は完全ではありませんが、オプションを利用できる場合は、アプリを独自のユーザー/グループに配置できます。既存のソケットパスがあり、それを所有していない場合は、リンクを解除してエラーメッセージを出力し、ユーザーまたはシステム管理者に分類させないでください。構成ファイルを使用して、簡単に変更可能にし、クライアントが利用できるようにすることで、機能する可能性があります。それを超えて、あなたはほとんどある種の発見サービスに行かなければなりません、これが本当に重要なアプリケーションでない限り、それは大規模なやり過ぎのように思えます。

全体として、これが実際には頻繁に発生しないという安心感を得ることができます。

于 2011-09-14T02:08:27.567 に答える