Created
July 14, 2016 10:55
-
-
Save kob-to-wni/1c2253c2674e01092fb07e7eccf4a1f4 to your computer and use it in GitHub Desktop.
UdpListenerService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Service; | |
import android.content.Intent; | |
import android.os.Handler; | |
import android.os.IBinder; | |
import android.support.annotation.Nullable; | |
import android.support.annotation.RequiresPermission; | |
import android.util.Log; | |
import java.io.IOException; | |
import java.net.DatagramPacket; | |
import java.net.DatagramSocket; | |
import java.net.SocketException; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.concurrent.CopyOnWriteArrayList; | |
/** | |
* UDPでデータを受信するサービス | |
* | |
* @author kob-to | |
*/ | |
public class UdpListenerService extends Service { | |
/** | |
* デバッグ用タグ | |
*/ | |
private static final String TAG = UdpListenerService.class.getSimpleName(); | |
/** | |
* UDPデータを受信した際のハンドラ | |
*/ | |
public static interface DatagramPacketReceivedHandler { | |
/** | |
* UDPデータを受信した際に呼ばれます | |
* @param packet UDPデータ | |
*/ | |
void onDatagramPacketReceived(DatagramPacket packet); | |
} | |
/** | |
* UdpListenerServiceのBinder | |
*/ | |
public static class Binder extends android.os.Binder { | |
/** | |
* UdpListenerServiceのインスタンス | |
*/ | |
private final UdpListenerService mService; | |
/** | |
* UdpListenerServiceのインスタンスを指定してBinderを初期化します | |
* @param service UdpListenerServiceのインスタンス | |
*/ | |
private Binder(UdpListenerService service) { | |
mService = service; | |
} | |
/** | |
* UdpListenerServiceのインスタンスを取得します | |
* @return | |
*/ | |
public UdpListenerService getService() { | |
return mService; | |
} | |
} | |
/** | |
* UDPの待ち受けポート | |
*/ | |
private static int port = 0; | |
/** | |
* UDPの割当ポート | |
*/ | |
private static int boundPort = 0; | |
/** | |
* 待ち受け状態 | |
*/ | |
private static boolean listening = false; | |
/** | |
* 受信バッファサイズ | |
*/ | |
private static int bufferSize = 1024; | |
/** | |
* ハンドラ | |
*/ | |
private final List<DatagramPacketReceivedHandler> mHandlerList = new CopyOnWriteArrayList<>(); | |
/** | |
* イベント発生用 | |
*/ | |
private Handler mHandler; | |
/** | |
* UDPソケット | |
*/ | |
private DatagramSocket mSocket = null; | |
/** | |
* 受信スレッド | |
*/ | |
private Thread mListeningThread = null; | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
mHandler = new Handler(getMainLooper()); | |
} | |
@Override | |
public void onDestroy() { | |
super.onDestroy(); | |
if (listening) { | |
// サービス破棄時には止める | |
stop(); | |
} | |
} | |
@Override | |
public @Nullable IBinder onBind(final Intent intent) { | |
return new Binder(this); | |
} | |
/** | |
* UDPの受信を開始します | |
*/ | |
@RequiresPermission("android.permission.INTERNET") | |
public synchronized void start() { | |
if (mListeningThread != null) { | |
throw new IllegalStateException("UdpListener was already started."); | |
} | |
if (BuildConfig.DEBUG) { | |
Log.i(TAG, "Starting UdpListener..."); | |
} | |
listening = true; | |
mListeningThread = new Thread(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
mSocket = new DatagramSocket(port); | |
} catch (SocketException e) { | |
if (BuildConfig.DEBUG) { | |
Log.e(TAG, e.getMessage(), e); | |
} | |
throw new RuntimeException(e); | |
} | |
boundPort = mSocket.getLocalPort(); | |
if (BuildConfig.DEBUG) { | |
Log.i(TAG, "UdpListener bounded to " + boundPort + " successfully. Receiving UDP packet..."); | |
} | |
byte[] buff = new byte[bufferSize]; | |
DatagramPacket packet = new DatagramPacket(buff, bufferSize); | |
try { | |
while (listening) { | |
mSocket.receive(packet); | |
synchronized (mHandlerList) { | |
for (final DatagramPacketReceivedHandler handler : mHandlerList) { | |
if (handler == null) { | |
continue; | |
} | |
byte[] cloneBuffer = Arrays.copyOf(buff, packet.getLength()); | |
final DatagramPacket clone = new DatagramPacket(cloneBuffer, cloneBuffer.length); | |
clone.setAddress(packet.getAddress()); | |
clone.setPort(packet.getPort()); | |
clone.setSocketAddress(packet.getSocketAddress()); | |
mHandler.post(new Runnable() { | |
@Override | |
public void run() { | |
handler.onDatagramPacketReceived(clone); | |
} | |
}); | |
} | |
} | |
} | |
} catch (IOException e) { | |
if (e instanceof SocketException) { | |
if (BuildConfig.DEBUG) { | |
Log.w(TAG, e.getMessage(), e); | |
} | |
} else { | |
if (BuildConfig.DEBUG) { | |
Log.e(TAG, e.getMessage(), e); | |
} | |
} | |
listening = false; | |
} finally { | |
if (BuildConfig.DEBUG) { | |
Log.i(TAG, "Receive UDP packet finished."); | |
} | |
if (mSocket != null && !mSocket.isClosed()) { | |
mSocket.close(); | |
} | |
} | |
} | |
}); | |
mListeningThread.start(); | |
} | |
/** | |
* UDPの受信を停止します | |
*/ | |
public synchronized void stop() { | |
if (mListeningThread == null) { | |
throw new IllegalStateException("UdpListener has not been started."); | |
} | |
if (BuildConfig.DEBUG) { | |
Log.i(TAG, "Stopping UdpListener..."); | |
} | |
listening = false; | |
mSocket.close(); | |
try { | |
mListeningThread.join(); | |
} catch (InterruptedException ignored) {} | |
mListeningThread = null; | |
} | |
/** | |
* ハンドラを追加します | |
* @param handler ハンドラのインスタンス | |
*/ | |
public void registerHandler(final DatagramPacketReceivedHandler handler) { | |
if (handler == null) { | |
throw new IllegalArgumentException("handler must not be null"); | |
} | |
mHandlerList.add(handler); | |
} | |
/** | |
* ハンドラを削除します | |
* @param handler ハンドラのインスタンス | |
*/ | |
public void unregisterHandler(final DatagramPacketReceivedHandler handler) { | |
if (handler == null) { | |
throw new IllegalArgumentException("handler must not be null"); | |
} | |
mHandlerList.remove(handler); | |
} | |
/** | |
* 割り当てられたポートを取得します | |
* @return 自動割り当てなら割り当てられたポート番号、それ以外は指定されたポート番号 | |
*/ | |
public static int getPort() { | |
return port == 0 ? boundPort : port; | |
} | |
/** | |
* 待ち受けポートを設定します | |
* @param value 0〜65535以下のポート番号。0は自動割り当て。 | |
*/ | |
public static void setPort(final int value) { | |
if (value < 0 || 65535 < value) { | |
throw new IllegalArgumentException("Port must be between 0-65535"); | |
} | |
if (listening) { | |
throw new UnsupportedOperationException("Can't change port while UDP listening"); | |
} | |
port = value; | |
} | |
/** | |
* 受信バッファのサイズを取得します | |
* @return 受信バッファのサイズ | |
*/ | |
public static int getBufferSize() { | |
return bufferSize; | |
} | |
/** | |
* 受信バッファのサイズを設定します | |
* @param value 受信バッファのサイズ | |
*/ | |
public static void setBufferSize(final int value) { | |
if (value < 1) { | |
throw new IllegalArgumentException("Buffer size must be >1"); | |
} | |
if (listening) { | |
throw new UnsupportedOperationException("Can't change buffer size while UDP listening"); | |
} | |
bufferSize = value; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment