Armadilloフォーラム

UDP通信について

appworks

2019年8月18日 13時17分

現在ArmadilloにアクセスポイントをたてTomcatにてWevアプリケーションを作成中です、
作成したWebページには無線環境から正常にアクセスできる状態ですが、その後ろで有線を用いて
機器と接続しUDP通信を行いたく考えております。

サンプルプログラムを作成いたしましたがUDPソケットから機器に対してブロードキャスト
(255.255.255.255)を送信しようとするのですが、IOExceptionで送信不可となります。
以下の点を確認いたしましたが手詰まりとなりご意見伺いたく。

・ファイアーウォールは受信送信含め、全て通過。
・有線は固定IP、ゲートウェイなしで設定した後Pingで疎通確認はできる状態。

もしかするとArmadilloの設定ではなく、TomcatもしくはJavaの実装の問題かもしれないのですが
何卒よろしくお願い申し上げます。

コメント

中村です。

> サンプルプログラムを作成いたしましたがUDPソケットから機器に対してブロードキャスト
> (255.255.255.255)を送信しようとするのですが、IOExceptionで送信不可となります。

やっていると思うのですが。。。
ソケットにSO_BROADCASTを設定してますか?

--
なかむら

中村さまご連絡ありがとうございます。
SO_BROADCASTオプションは追加しており、開発環境では送信できている状態です。

少し思ったのですが、ブロードキャスト送信する際に使用するローカルアドレスについて
優先度などあるのでしょうか?
開発環境と違いアクセスポイント化しているので、無線と有線のIPがあるのですが
この辺関係ありますでしょうか?

中村です。

> SO_BROADCASTオプションは追加しており、開発環境では送信できている状態です。

javaのプログラムの問題ということではなさそうですね。

> 少し思ったのですが、ブロードキャスト送信する際に使用するローカルアドレスについて
> 優先度などあるのでしょうか?
> 開発環境と違いアクセスポイント化しているので、無線と有線のIPがあるのですが
> この辺関係ありますでしょうか?

UDP送信だけのできるだけ小さくて簡単なテストプログラムを作って、
問題がでていない開発環境と問題が出る実機とそれぞれで動かして、
どこに問題があるのかを調べるのがいいと思います。
たぶん言語の影響はないとは思いますけど、
まずは、細かなところを確認できるCがいいかも。

--
なかむら

中村様

お世話になります。
ご返信ありがとうございます。

確認いたしましたところ、アクセスポイント構築により、wifiとイーサネット2つアドレスが存在することからどちらにブロードキャストするか指定が必要でした。

丁寧にご対応頂きありがとうございました。

中村です。

> > > 開発環境と違いアクセスポイント化しているので、無線と有線のIPがあるのですが
と書かれていたのに、このこと(NICが2つあること)は無視したような
投稿になってしまっていましたが、解決できたようですね。

NICが複数あるとき、255.255.255.255でブロードキャストを投げると、
すべてのインターフェースに送信されると思っていたのですけど、
そうではなく送信エラーになってしまうのですね。

たとえば、192.168.0.0/24と192.168.1.0/24というインターフェースがあったとき、
ブロードキャストの宛先を192.168.0.255や192.168.1.255とすれば、
使用される「送信元」インターフェースは自動的に振り分けられると思います。

今回、
> ...どちらにブロードキャストするか指定が必要でした。
とのことですが、
どのような方法で指定をしたのかを教えていただけますでしょうか?

よろしくお願いします。

--
なかむら

中村様

ご連絡ありがとうございます。
ソースは以下の用に修正しました。

-----------------------------------------------------------------
//有線LAN接続されているか確認
//別のIPで接続しようとするとIOException発生し、その後接続不可となるため必ずループさせる必要がある
while(true) {
Enumeration enuIfs = NetworkInterface.getNetworkInterfaces();
if (null != enuIfs)
{
while (enuIfs.hasMoreElements())
{
System.out.println("INTERFECE FOUND");
NetworkInterface ni = (NetworkInterface)enuIfs.nextElement();
System.out.println("getDisplayName:\t" + ni.getDisplayName());
System.out.println("getName:\t" + ni.getName());
Enumeration enuAddrs = ni.getInetAddresses();
while (enuAddrs.hasMoreElements())
{
InetAddress in4 = (InetAddress)enuAddrs.nextElement();
//192.168.0.3が存在するか接続確認
if(in4.getHostAddress().equals(Define.ETHERNET_IP_ADDRESS)) {
//本番環境ではWifiIPもあるので有線の固定IPに指定する
udp = new DatagramSocket(localPort,InetAddress.getByName(Define.ETHERNET_IP_ADDRESS));
udp.setReceiveBufferSize(RECV_BUFFER_SIZE_MAX);
return true;
}
System.out.println("getHostAddress:\t" + in4.getHostAddress());
}
}
}
//接続するまでループ
Thread.sleep(1000);
}
-----------------------------------------------------------------

上記内以下で有線接続がなされるまでループ、固定IP有無を確かめて指定してあげるように修正しています。
udp = new DatagramSocket(localPort,InetAddress.getByName(Define.ETHERNET_IP_ADDRESS));

ただまた別の問題があり解析中なのですが、この待機処理のwhile(true)につきまして
一度LANが抜かれた場合も再度検索するシーケンスを通り上記ソース箇所に戻ってくるのですが
なぜかループ処理が途中で止まってしまいます。

テスト環境(Windows上のTomcat)では正常にソース動作、再接続できるのですが、Armadilloに構築した環境で発生する
ので環境依存かと考えております。

OS上で無限ループに陥るような処理についてはフリーズさせるなど何か考慮すべき点等ございますでしょうか?

追加情報ですが、アプリケーション自体はアクセス可能なので終了されておらず
Eceptionも吐いていない状態です。
上記While中のログを2回通った後、処理フリーズしているようです。

中村です。

使われているコードの元は、
https://www.itmedia.co.jp/enterprise/articles/0407/27/news031.html
の「2重ループで全部列挙」のサンプルコードですね。
このサンプル自体が、この記事オリジナルかどうかは不明ですけど。

> 一度LANが抜かれた場合も再度検索するシーケンスを通り上記ソース箇所に戻ってくるのですが
> なぜかループ処理が途中で止まってしまいます。

192.168.0.3が一時的になくなってしまうのが問題なのでしょうね。たぶん。

どうやって回避するか、そもそも、原因が何なのかもわからないですけど、
有線LANのIPアドレスを固定としているなら、面倒な処理は全部やめて、
ブロードキャストの宛先を192.168.0.255にしてはどうですか?

--
なかむら

中村様

お知恵を頂き大変ありがとうございます。

>192.168.0.3が一時的になくなってしまうのが問題なのでしょうね。たぶん。

正しくこれでした。基本的にループで監視し続けるのが良くないですよね。
切断されてもすぐにリストから消されることがないのでIPをつかみに行こうとすると
すでに抜けている場合は状態異常に陥っていました。
Windows環境ではスペック?の違いから切断が速く走りたまたまうまく動いていたようです。

UDP間でパケットを飛ばして対向機と疎通確認していますので、
ネットで調べたセオリー通りアプリで受信タイムアウトを設け切断検知から再接続
処理へ向かうように修正しました。

何度もお知恵を頂き大変ありがとうございました。
また何かございましたロ何卒宜しくお願い致します。