Delphi10.3CEのIndy10で、IdUDPServerのBroadcastについて教えてください。
IdUDPServerを使用して同じソースで送受信しているのですが、
Windows同士では問題なくできるのですが、
Windows-Android間のAndroidの受信のみができません。
(Sendでは問題なく送受信できています)
UDPReadを疑ってしまいますが、
色々検索すると「BroadcastReceiver」でいくつかヒットするのですが読んでもさっぱりわかりません。
そもそも関係あるのかどうかも不明です。
IdUDPServerのBroadcastをAndroidで受信する方法を教えてください。
Indy10で、しつこい質問ばかりですみません。
よろしくお願いいたします。
回答でも何でもないのですが、デバッグ実行でIdUDPServer.pasのTIdUDPListenerThread.Runの中の438行目付近、
| if ByteCount >= 0 then
| begin
| SetLength(FBuffer, ByteCount);
のSetLengthの行にブレークポイントを設定して、他からBroadCastしたときにこの行に到達するかどうかを、まずは確認してみてはいかがでしょう?
ごめんなさい
話が難しすぎて何もできません。
https://qiita.com/niusounds/items/c02bee3001c2ff8056cf
Androidではマルチキャストパケットを受信するためにWifiManager.createMulticastLockを使ってロックを作成し、
WifiManager.MulticastLock.acquire()を呼ぶ必要があります。
とか?
このへんですかね?
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
色々ありがとうございます
残念ですが、私のスキルをはるかに超えてしまっています。
教えていただいたStack Overflowのソースをunitで追加して、
記事あるステップを記述してみましたがダメでした。
コンパイルエラーを取るのみで、そもそも全然理解できていません。
私には無理かなあって。。。
詳しいことはわかりませんが、Unitをコピーとかではなく、ブリッジファイル
を作成するということのようです。TLBの読込みみたいなもんですか?
[山本隆の開発日誌]
https://www.gesource.jp/weblog/?p=6846
例で使っているメンバは違いますが、たぶん同じクラスですよね。
見当違いだったらすみません。
色々ありがとうございます。
「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の状態に応じた対応が必要なのでしょうか?
皆さんに助けていただいたのですが、違い方向に行ってしまい大変恐縮です。
最終的に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;
takeさん、ありがとうございます。
まず、私のスキル不足ですみません、
Android側(B)アプリ起動時(FormCreate)に「(B) サーバーとして起動」を記述して、
サーバー側の受信を待っている状態ですが、
このWifiLock/WifiUnLockの指定する場所を教えてください。
あと。。。
「(B) ブロードキャストの受信と返信 ついでに接続 」が受信できない状態ですので、
サーバー側のIPアドレスを知ることができないのです。
サーバー側はクライアント側アプリが、どこにどれだけいるのかわからないのでBroadcastしようとしています。
Broadcast受信がでればお互いのIPアドレスを知ることができますので、あとはSendが使えます。
変なこと書いてたらご指摘ください。
よろしくお願いいたします。
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 を色々使って見るしかないかもしれません。
教えていただいたコードや検索で見つけた色々なパターンをやってみました。
WiFiマネージャーのロックの取得を確認(isHeld=True)もしながらやってみましたが、
どれも確実にUDPブロードキャストを受信できるものがありませんでした。
Javaなら上手くいっている人が多いようです。
Delphiでは、そろそろ潮時かなあ。。。
機種やAndroidバージョンなどに依存したりするのかな?
たくさんの方々に助けていただいたことに感謝します。
邪道な対処ですが、以下のようにアプリ起動時にWifiを再接続することで100%の確立で受信できました。
wifiManager.disconnect
wifiManager.enableNetwork
wifiManager.reconnect
ちなみに、multiCastLockのisHeldはFalseのままです。
論理的な説明はできませんし、再接続による他への影響も多々ありますが、やりたいことができました。
未解決のままになっているのが気になりましたので、これで解決とさせていただきます。