10

LAN 上でメッセージを 1 秒程度でブロードキャストするサーバー/サービスを作成しようとしています。サービス ディスカバリのようなものです。

メッセージは、同じマシン上または異なるマシン上にある複数のクライアント プログラムによって受信される必要があります。ただし、同時に実行されている各マシンで複数のプログラムが存在する可能性があります。

indy 9.0.18でdelphi7を使用しています

私が立ち往生している場所は、UDP(TIdUDPClient / Server)またはIP MultiCast(TIdIPMCastClient / Server)を使用する必要があるか、それが可能かどうかです...

マシンごとに1つのクライアントを使用してIPマルチキャストで動作させることができましたが、さまざまなバインディングで何度も試行した後でも..最大/最小ポートなど、解決策が見つからないようです.

4

5 に答える 5

8

SO_REUSEADDRソケットオプションを探していると思います。ソケットにそのオプションを設定すると、複数のソケットが同じポートでリッスンできるようになります。マルチキャストの場合、Windowsは、メッセージがすべてのソケットに配信されることを保証します(それ以外の場合、メッセージはランダムに1つのソケットにのみ送信されます)。

通常、これはsetsockoptを呼び出すことで行いますが、私はDelphi開発者ではないため、APIがどのように見えるかわかりません。この質問は、Delphiで同様のことをしている人の例を示しているようです。

于 2010-04-14T03:19:21.610 に答える
5

私はこれをやったことがありませんが、「メールスロット」が必要なようです。ローカル ネットワーク上でメッセージをブロードキャストし、返信方法を知っている他のワークステーションからの返信を受け取ります。これが、人気のある「アルマジロ」ライセンス マネージャーの仕組みです (登録キーが「オーバーサブスクライブ」されないようにするため)。私のアプリ (ClipMate) は Armadillo を保護ラッパー (シェアウェア ラッパー) として使用しています。登録ユーザーがアプリを実行すると、同じネットワーク上の他のマシンで同じキーが使用されているかどうかがチェックされます。基本的には、「私はライセンス 1234 を使用していますが、あなたはどうですか?」と言っています。応答を待ちます (起動時に別のスレッドでこれを行うので、起動をブロックしません)。他のワークステーションが同じキーを使用していると報告した場合、ライセンスに含まれるシート数と照らし合わせてカウントを確認します。Windows7でこれほど堅牢かどうかは完全にはわかりません....

于 2010-04-09T03:16:10.680 に答える
2

それは間違いなく可能です。

「UDPまたはマルチキャスト」に関しては、リンゴとオレンジを話している. マルチキャストは IP の概念であるため、マルチキャスト IP またはブロードキャスト IP でUDPを問題なく使用できます。

すべてのクライアントをリンクローカルにするという制限 (ルーターなどは一般にブロードキャスト パケットを転送しない) に問題がない場合は、ブロードキャストを使用することをお勧めします。TIdUdpBase.Broadcast は、ここであなたの友達になります。

更新:マルチキャストでもブロードキャストでも、特定の IP/ポート ペアにバインドできるソケットは 1 つだけです。したがって、複数のクライアントがすべて同じブロードキャスト/マルチキャストをリッスンする必要がある場合は、追加のディスパッチャ クライアントが必要になると思います。このディスパッチャ クライアントはブロードキャストを受信し、マシン上のすべてのクライアントに通知します。

各クライアント内には、「ブロードキャストが送信されるポートにバインドしてみてください。できる場合は、そのポートにディスパッチャ クライアントをセットアップしてください。できない場合は、ディスパッチャがすでに作成されており、そのディスパッチャに登録してください。」

その登録プロセスは、ローカルホスト IP で使用可能な任意のポートにバインドし、ディスパッチャーに「この IP/ポートにブロードキャストを送信してください」と言うだけで済みます。

更新: Christopher Chaseの考えは正しいです。IdIPMCastClient にパッチを適用し、プロパティ ReuseAddr: Boolean を追加し、TIdIPMCastClient.GetBinding を追加して変更したことを除いて、彼とほぼ同じソリューションを完成させました。

if Self.ReuseAddr then begin
  SetReuseAddr := Id_SO_True;
  Bindings[i].SetSockOpt(Id_SOL_SOCKET, Id_SO_REUSEADDR, @SetReuseAddr, Sizeof(SetReuseAddr));
end;

AllocateSocket と Bind の呼び出しの間 (SetReuseAddr: Integer)。

于 2010-04-12T14:35:31.973 に答える
1

shf301からのヒントで、これは私がそれで動作するコードです

新しい TIdIPMCastClient を作成しました

 TIdReUseIPMCastClient = class(TIdIPMCastClient)
  private
    procedure SetReUseAddr(InBinding: TIdSocketHandle; const Value: boolean);
  protected
    function GetBinding: TIdSocketHandle; override;
  public
  end;

手順を追加しました

procedure TIdReUseIPMCastClient.SetReUseAddr(InBinding: TIdSocketHandle; const Value: boolean);
var
  tempi: integer;
begin
  if Assigned(InBinding) and InBinding.HandleAllocated then
    begin
    tempi := iif(Value, 1, 0);
    InBinding.SetSockOpt(Id_SOL_SOCKET, Id_SO_REUSEADDR, PChar(@tempi), SizeOf(tempi));
    end;
end;

TIdIPMCastClient からGetBindingコードをコピーし、バインドの前に SetReUseAddr を追加しました

  Bindings[i].AllocateSocket(Id_SOCK_DGRAM);
  SetReUseAddr(Bindings[i], True);
  Bindings[i].Bind;
于 2010-04-14T06:23:49.060 に答える
1

RemObjects には、これに対する優れた解決策があります: ROZeroConf

TROBroadcastChannelそれが利用可能になる前に、私は RemObjects SDK (ベースの UDP と Indy) を使用して自分でそのようなものを作成しました。そのコンポーネント内で、応答TIdUDPBase.Broadcastを送信および受信するために呼び出します。TIdUDPClient.ReceiveBuffer

(ところで、UDP ブロードキャストは同じネットワーク/サブネットでのみ機能します。ROZeroConfの方が優れたソリューションです)

于 2010-04-09T06:22:44.037 に答える