UDP 브로드캐스팅을 통한 근거리 데이터 교환 앱을 짜고 있습니다.
소켓 부분은 서비스 클래스를 만들어서 따로 스레드를 구현하여 돌리고 있고,
메인 액티비티에서는 스레드 시작과 종료, UI 부분만 담당하고 있습니다.
두 장치 이상이 서로가 브로드캐스팅하면서 데이터를 주고 받는 것이 정상인데,
이게 화면이 켜져 있을 땐(Sleep 상태가 아닐 때) 정상적으로 데이터를 교환하는데,
화면이 꺼지면(Sleep 상태면) send만 되고 receive는 되지 않는 현상이 발생합니다.
온갖 실험과 반복과 질문을 통해서도 해결이 안되기에 안드로이드 API 자체의 오류가 아닌가 의심이 될 정도입니다.
메인 액티비티의 코드는 아래 안펍 게시물을 확인해주세요.
http://www.androidpub.com/2562377
본 게시판은 글자수 초과가 있네요. 아무래도 코드가져오기 금지 인것 같습니다. 죄송합니다.
아래는 서비스 부분 클래스입니다.
public class LocalService extends Service {
WifiManager.WifiLock wifiLock = null;
PowerManager.WakeLock wakeLock = null;
static DatagramSocket socket;
MessageReciver messageReceiver;
MessageSender messageSender;
private volatile boolean keepRunning = true;
public static String SERVER_IP = "255.255.255.255";
public static int SERVER_PORT = 15464;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
try {
if (wifiLock == null) { // 와이파이락 부분
WifiManager wifiManager = (WifiManager) this.getSystemService(this.WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock("wifilock");
MulticastLock lock = wifiManager.createMulticastLock("multicast");
lock.acquire();
wifiLock.setReferenceCounted(true);
wifiLock.acquire();
}
if (wakeLock == null) { // 웨이크락 부분
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "wakelock");
wakeLock.acquire();
}
// UDP 소켓 생성, 브로드캐스트 모드
socket = new DatagramSocket(SERVER_PORT);
socket.setBroadcast(true);
// 스레드 객체 생성, UDP 패킷 수신과 송신
messageReceiver = new MessageReciver();
messageSender = new MessageSender();
}
catch (Exception e) {
Log.e("SOCKET", e.getMessage());
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// 스레드 시작
messageReceiver.start();
messageSender.start();
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
// 스레드 중단
keepRunning = false;
messageReceiver.interrupt();
messageSender.interrupt();
// 와이파이락, 웨이크락 종료
if (wifiLock != null) {
wifiLock.release();
wifiLock = null;
}
if (wakeLock != null) {
wakeLock.release();
wakeLock = null;
}
messageReceiver = null;
messageSender = null;
// 소켓 닫기
socket.close();
socket = null;
System.gc();
}
// 메인 액티비티와 연결하기 위핸 수신 핸들러
Handler handler = new Handler() {
public void handleMessage(Message message) {
super.handleMessage(message);
// 받은 패킷의 아이피의 마지막 주소를 메인 액티비티에 전송
String[] addr = ((String)message.obj).split("\\.");
MainActivity.recive(Integer.parseInt(addr[3]));
}
};
// 패킷 수신 스레드
public class MessageReciver extends Thread {
public void run() {
try {
while (keepRunning) {
// 패킷 수신
byte[] buffer = new byte[1000];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet); // ** 스레드가 블락되는 메소드 ** 이 메소드 도중에 프로그램이 종료되면 예상치않은 오류 메시지가 뜸 **
// 패킷의 데이터는 버리고, 아이피주소만 핸들러로 전송
Message message = handler.obtainMessage(1, packet.getAddress().getHostAddress());
handler.sendMessage(message);
}
} catch (IOException e) {
Log.e("recvTHREAD", e.getMessage());
e.printStackTrace();
}
}
}
// 패킷 송신 스레드, 1초마다 반복 송신
public class MessageSender extends Thread {
public void run() {
try {
while (keepRunning) {
// 더미 패킷을 1초마다 브로드캐스트 송신
String text = new String("signal");
DatagramPacket packet = new DatagramPacket(text.getBytes(), text.getBytes().length, InetAddress.getByName(SERVER_IP), SERVER_PORT);
socket.send(packet);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Log.e("sendTHREAD", e.getMessage());
e.printStackTrace();
} catch (IOException e) {
Log.e("sendTHREAD", e.getMessage());
}
}
}
}
이 프로그램을 실행하면
0
0
으로 시작해서, 자신것이 켜져 있는 상태에서는 위에 텍스트 숫자 0이 1씩 증가합니다.
이 상태에서 다른 안드로이드폰을 가져와서 같은 프로그램을 또 실행하면 아래쪽 숫자도 1씩 증가하게 됩니다.
하지만 잠시 슬립상태로 화면을 껏다가 다시 켜면, 위쪽 숫자만 증가되어 있고, 아래쪽 숫자는 멈춰있다가
다시 켜면 그때서야 올라가는 것을 확인할 수 있습니다. 함께 켠 다른 폰도 마찬가지고요.
즉, 슬립상태에서는 자신이 보낸 패킷만 읽을 수 있고, 외부 수신은 전혀 되지 않는다는 걸 알 수 있습니다.
와이파이락과 웨이크락도 걸려있는 상태도인데도 말이죠...
너무 어이가 없고 해결이 안되서 안펍 고수님들께 여쭤보고자 염치없이 코드를 들고왔습니다.