IdUDPServerのBroadcastをAndroidで受信する方法を教えてください。

解決


デンカ  2020-02-09 08:32:06  No: 148543  IP: 192.*.*.*

Delphi10.3CEのIndy10で、IdUDPServerのBroadcastについて教えてください。

IdUDPServerを使用して同じソースで送受信しているのですが、
Windows同士では問題なくできるのですが、
Windows-Android間のAndroidの受信のみができません。
(Sendでは問題なく送受信できています)

UDPReadを疑ってしまいますが、
色々検索すると「BroadcastReceiver」でいくつかヒットするのですが読んでもさっぱりわかりません。
そもそも関係あるのかどうかも不明です。

IdUDPServerのBroadcastをAndroidで受信する方法を教えてください。
Indy10で、しつこい質問ばかりですみません。
よろしくお願いいたします。

編集 削除
HFUKUSHI  2020-02-10 02:31:28  No: 148544  IP: 192.*.*.*

回答でも何でもないのですが、デバッグ実行でIdUDPServer.pasのTIdUDPListenerThread.Runの中の438行目付近、
|       if ByteCount >= 0 then
|       begin
|         SetLength(FBuffer, ByteCount);
のSetLengthの行にブレークポイントを設定して、他からBroadCastしたときにこの行に到達するかどうかを、まずは確認してみてはいかがでしょう?

編集 削除
デンカ  2020-02-10 03:58:33  No: 148545  IP: 192.*.*.*

ごめんなさい
話が難しすぎて何もできません。

編集 削除
AAA  2020-02-10 08:55:19  No: 148546  IP: 192.*.*.*

https://qiita.com/niusounds/items/c02bee3001c2ff8056cf
Androidではマルチキャストパケットを受信するためにWifiManager.createMulticastLockを使ってロックを作成し、
WifiManager.MulticastLock.acquire()を呼ぶ必要があります。
とか?

編集 削除
HFUKUSHI  2020-02-10 09:22:52  No: 148547  IP: 192.*.*.*

このへんですかね?
Delphi XE5 TIdUDPServer does not receive anything on Android - Stack Overflow
https://stackoverflow.com/questions/19040674/delphi-xe5-tidudpserver-does-not-receive-anything-on-android

編集 削除
デンカ  2020-02-11 08:18:52  No: 148548  IP: 192.*.*.*

色々ありがとうございます

残念ですが、私のスキルをはるかに超えてしまっています。
教えていただいたStack Overflowのソースをunitで追加して、
記事あるステップを記述してみましたがダメでした。

コンパイルエラーを取るのみで、そもそも全然理解できていません。
私には無理かなあって。。。

編集 削除
Nov  2020-02-11 15:03:35  No: 148549  IP: 192.*.*.*

詳しいことはわかりませんが、Unitをコピーとかではなく、ブリッジファイル
を作成するということのようです。TLBの読込みみたいなもんですか?
[山本隆の開発日誌]
https://www.gesource.jp/weblog/?p=6846
例で使っているメンバは違いますが、たぶん同じクラスですよね。
見当違いだったらすみません。

編集 削除
デンカ  2020-02-12 04:58:20  No: 148551  IP: 192.*.*.*

色々ありがとうございます。

「Java2OPでWifiManagerクラスのブリッジファイルを作成」をやってみました。
BroadcastをAndroidで受信できました!!

しかし、変なことが起こっています。
Androidアプリを再起動するとダメになってしまいました。

そこで、いろいろ試した結果を書きます。(こんなことが起こってます)

1) Wifi切断状態で、Androidアプリを起動します。
2) Sendを実行
3)「Socketエラー #101 ネットワークが到達できません。」が発生。
4) Wifiを接続
5) Sendを実行すると正常(Windowsに到達)かつ、WindowsからのBroadcastをAndroidで受信できました。
6) Androidアプリを終了します。
7) Androidアプリを起動します。
8) Sendを実行 相手に届かずかつ、Broadcastも受信できず。
9) 1から繰り返すこと同じ結果になりました。

今までは、4以降でテストしてました。結果がダメでした。

次に、WifiManagerとの関係が知りたかったので、
WifiManager関連のステップを全て削除しましたところ、
1から8とまったく同じ現象が発生しました。

どうなっているのかサッパリです。

WifiManagerを使って、Wifiの状態に応じた対応が必要なのでしょうか?
皆さんに助けていただいたのですが、違い方向に行ってしまい大変恐縮です。

編集 削除
take  2020-02-13 01:17:43  No: 148555  IP: 192.*.*.*

最終的にWindows側(A)がサーバーでAndroid側(B)がクライアントの構成
Windows側からネットワーク全体にブロードキャスト送信してサーバーのIPアドレスを通知
Android側でブロードキャスト受信が出来れば、クライアントとして接続先がわかるので
サーバーのIPアドレスを指定する必要が無く便利

という仕様で(例1)に (A)と(B)の処理を記述

【現象】これがAndroidでうまくいったりいかなかったりする。
【解決1】Java2OPでWifiManagerクラスを使ってWifiの有効無効を制御でブロードキャストがうまくいった。
↑これはよくわからない

【原因】
Androidの省エネによる最適化でブロードキャストは制限があると思われます。

Stack Overflowのソースを参考に対応コンパイラも環境もありませんが書いてみました。

function WifiLock : JWiFiManager;
var
  Obj: JObject;
begin
  Obj := SharedActivityContext.getSystemService(TJContext.JavaClass.WIFI_SERVICE);
  if not Assigned(Obj) then  raise Exception.Create('Could not locate Wifi Service');
  multiCastLock  := Obj.createMulticastLock(StringToJString('lock'));
  multiCastLock.acquire();
end;

function WifiUnLock : JWiFiManager;
var
  Obj: JObject;
begin
  Obj := SharedActivityContext.getSystemService(TJContext.JavaClass.WIFI_SERVICE);
  if not Assigned(Obj) then  raise Exception.Create('Could not locate Wifi Service');
  multiCastLock := Obj.createMulticastLock(StringToJString('lock'));
  multiCastLock.release();
end;

(例1)

Windows同士だったらIndyのUdpServerで

(B) サーバーとして起動
  UdpServerB.Active := True;

(A) ブロードキャスト送信
  UdpServerA.BroadcastEnabled := True;
  UdpServerA.Active := True;
  UdpServerA.Broadcast('アプリを識別する文字列'#13#10, (B)のサーバーのポート);
  
(B) ブロードキャストの受信と返信 ついでに接続
procedure TForm1.UdpServerUDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
var
  ip, s: string;
begin
  s  := '';
  SetLength(s, AData.Size);
  AData.Read(s[1], Length(s));
  ip := ABinding.PeerIP;
  UdpServerB.Send(ip, (B)のサーバーのポート, s);
  UdpClientB.Host := ip;
  UdpClientB.Connect;
end;

(A) ブロードキャストの返信を受信
procedure TForm1.UdpServerUDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
var
  ip, s: string;
begin
  s  := '';
  SetLength(s, AData.Size);
  AData.Read(s[1], Length(s));
  ip := ABinding.PeerIP;
end;

編集 削除
デンカ  2020-02-13 04:23:41  No: 148556  IP: 192.*.*.*

takeさん、ありがとうございます。

まず、私のスキル不足ですみません、
Android側(B)アプリ起動時(FormCreate)に「(B) サーバーとして起動」を記述して、
サーバー側の受信を待っている状態ですが、
このWifiLock/WifiUnLockの指定する場所を教えてください。

あと。。。

「(B) ブロードキャストの受信と返信 ついでに接続 」が受信できない状態ですので、
サーバー側のIPアドレスを知ることができないのです。


サーバー側はクライアント側アプリが、どこにどれだけいるのかわからないのでBroadcastしようとしています。
Broadcast受信がでればお互いのIPアドレスを知ることができますので、あとはSendが使えます。

変なこと書いてたらご指摘ください。
よろしくお願いいたします。

編集 削除
take  2020-02-13 05:38:54  No: 148557  IP: 192.*.*.*

PCで動作してIP取得出来ていれば仕様としてはあっていると思います。

他の方が参考にと貼ったリンク先のソースを再度参考に
https://stackoverflow.com/questions/19040674/delphi-xe5-tidudpserver-does-not-receive-anything-on-android

AndroidでUDPブロードキャスト通信をするときの注意
https://qiita.com/niusounds/items/f080537417a0512acf15

上記のリンク先からさらにリンクされているWiFiマネージャーのロックを取得する方法
https://pzoleeblogen.wordpress.com/2014/03/04/android-udp-broadcast-message-is-not-received/

ブロードキャストパケットの受け取りを制限を解除するためにはWiFiマネージャーのロックの取得と解放が必要。

日本語の情報は無く、さらにDelphiから操作するための情報も無いようです。
getSystemService を色々使って見るしかないかもしれません。

編集 削除
デンカ  2020-02-14 08:14:29  No: 148561  IP: 192.*.*.*


教えていただいたコードや検索で見つけた色々なパターンをやってみました。

WiFiマネージャーのロックの取得を確認(isHeld=True)もしながらやってみましたが、
どれも確実にUDPブロードキャストを受信できるものがありませんでした。

Javaなら上手くいっている人が多いようです。
Delphiでは、そろそろ潮時かなあ。。。

機種やAndroidバージョンなどに依存したりするのかな?
たくさんの方々に助けていただいたことに感謝します。

編集 削除
デンカ  2020-02-27 02:12:52  No: 148595  IP: 192.*.*.*

邪道な対処ですが、以下のようにアプリ起動時にWifiを再接続することで100%の確立で受信できました。
 wifiManager.disconnect
 wifiManager.enableNetwork
 wifiManager.reconnect

ちなみに、multiCastLockのisHeldはFalseのままです。

論理的な説明はできませんし、再接続による他への影響も多々ありますが、やりたいことができました。
未解決のままになっているのが気になりましたので、これで解決とさせていただきます。

編集 削除