2011년 10월 8일 토요일

DatagramChannel 사용 주의

모바일 장치의 중요한 기능은 네트워크 이다.
필요 이상의 네트워크 기능 사용을 하게 되면 예상치 못한 문제에 봉착할 수 있다.
그 예상치 못한 문제 중 하나가 DatagramChannel 을 사용하였을 때 나타났다.

먼저 DatagramSocket 대신 DatagramChannel 을 사용하는 이유는 Selector 를 사용하여 읽거나 쓸 수 있는 정보가 있을 때만 receive 함수를 부르게 할 수 있기 때문이다.

하지만 주기적으로 DatagramChannel 의 receive 함수에서 시간이 오래 걸리는 문제가 발생했다.
정확한 증상은 모바일 네트워크 기능이 활성화 된 상태에서 DatagramChannel 을 이용해서 비디오 스트림을 받기만 하였는데 약 30초 마다 1~2 초의 데이터 유실 또는 데이터 블로킹으로 인해 데이터가 한꺼번에 많이 들어오는 증상이 있었다.

문제는 특이하게도 DatagramChannel 의 receive 함수에 있었다.
receive 함수의 구현을 보려면 안드로이드 소스 코드의 DatagramChannelImpl.java 파일을 찾아 receive 함수를 확인해 보면 된다.
http://www.java2s.com/Open-Source/Android/android-core/platform-libcore/org/apache/harmony/nio/internal/DatagramChannelImpl.java.htm

위 링크에 보면 receive 함수 안에서 receiveImpl 함수를 부르고 있다.
receiveImpl 함수가 실제 데이터 수신을 하는 부분이며 receiveImpl 함수 마지막 부분에 보면 getSocketAddress 함수가 불리고 있다.
getSocketAddress 함수는 DatagramPacket 의 함수이며 getSocketAddress 함수가 하는 일을 보면 InetSocketAddress 를 생성하는 사실을 알 수 있다.
http://www.java2s.com/Open-Source/Android/android-core/platform-libcore/java/net/DatagramPacket.java.htm

InetSocketAddress 의 생성자 코드에는 getHostName 이라는 함수를 부르고 있고 이 getHostName 이라는 함수는 name server 즉 DNS 에 query 를 날려 해당 주소 정보를 얻어오는 작업을 한다.
http://www.java2s.com/Open-Source/Android/android-core/platform-libcore/java/net/InetSocketAddress.java.htm

그렇다면 매번 receive 함수에서 작업이 오래 걸리지 않고 일정한 주기로 증상이 보이는 이유는 무엇일까? 더 정확한 이유를 찾으려면 어디까지 내려가야 할 지 모르겠다. 다만 예상하기로 DNS cache 같은 개념이 존재하고 cache 가 refresh 되는 시간이 있어서 그러지 않을까 생각한다.

어찌하였든 결국 DatagramChannel 을 DatagramSocket 으로 변경했다. DatagramSocket 의 receive 는 데이터를 얻는 동작만 하고 데이터를 보낸 쪽의 host name 을 얻지 않는다.

생각해 보면 host name 을 얻고 안 얻고는 사용자의 몫으로 남겨놓아야 했다고 생각한다.

댓글 없음:

댓글 쓰기