본문 바로가기

TechLog

Windows Phone 7.1에서의 UDP 패킷 송/수신 트릭

Windows Phone(이하 WP) 7.1 SDK에서는 소켓 바인딩이 불가능하다는 이야기를 지난 번 포스팅에서 언급한 적이 있었다. TCP의 경우 클라이언트가 서버에 연결해 소켓 연결이 확립되고 나면 서로 패킷을 주고 받을 수 있는 상태가 되지만, UDP는 소켓 바인딩이 불가능하면 수신 자체가 불가능하다. 이에 대한 이야기가 좀 장황해져서 정리할 필요성이 있지 않나 하고 느끼게 됐는데, 일단 SDK에서 실제로 제공하는 송신 / 수신 메서드에 대해서는 언급하지 않고, 개념적인 부분만 최대한 간략하게 설명해 보도록 하겠다. (하지만 작동 방식이 워낙 기괴해서 … 이 글이 WP 7.1용 UDP 소켓 프로그래밍을 하는 사람에게 도움이 되기만을 바랄 뿐이다)

 

 

1. WP 7.1 SDK로는 UDP 소켓으로 바인딩하는 코드를 만들 수가 없다.

다시 말해, WP 7.1 SDK에서는 특정 포트에서 UDP 패킷을 수신하는 프로그램을 만들 수가 없다.

 

2. WP 7.1 SDK에서는 오로지 UDP 서버의 특정 포트로 패킷을 전송하는 작업만 가능하다.

WP 클라이언트를 C, 8000번 포트를 바인딩한 UDP 서버 프로그램이 실행되는 서버를 S라고 가정해 보자:

C:? ---------------> S:8000

위 도식을 보면 : 뒤에 붙는 것이 포트 번호임을 알 수 있다. TCP/UDP 통신에 익숙한 사람은 알고 있겠지만, TCP/UDP 통신이 이루어질 때 서버측에서만 소켓에 포트 번호가 붙는 것이 아니라, 연결을 시도하는 클라이언트의 소켓 측에도 포트 번호가 붙게 된다. 이 부분에서 WP 7.1 SDK의 기괴한 UDP 소켓의 작동 방식이 드러나는데,

 

3. 서버가 WP 7.1 클라이언트로부터 UDP 패킷을 수신하면, 서버는 클라이언트의 UDP 소켓이 어느 포트에 바인딩되어 있는지를 알 수 있다.

참고로, WP 7.1의 UDP 소켓은 자신이 UDP 패킷을 송신할 때에도 스스로 자신이 어느 포트에 바인딩되어 있는지 알 수 없다.

또한 이 때 WP 7.1 클라이언트의 UDP 포트는 임의로 결정된다. (경험적으로 49001~65535번 사이에서 자동으로 할당되는 것 같지만, 정확하지는 않다)

C:?                      S:8000   { 49001번 포트에서 패킷이 왔구나! )

 

4. 이제 서버는 클라이언트의 해당 포트로 UDP 패킷을 전송하면 된다.

※ 이 부분이 중요하다! : 이 때 서버는 클라이언트로부터 패킷을 수신한 즉시 응답 패킷을 전송해야 한다.

최초에 WP 7.1 클라이언트의 UDP 소켓이 UDP 서버에 패킷을 전송하고 나면, 해당 UDP 소켓의 포트는 약 5초간 바인딩된다. (다시 말해, 5초 후에 해당 포트는 닫힌다)

위 내용으로 미루어 짐작할 수 있겠지만, WP 7.1 클라이언트가 어딘가로 패킷을 전송하기 전에는 WP 7.1 클라이언트의 어떤 포트도 열리지 않는 상태가 된다.

C:49001 <------------- S:8000
(5초 이내에 응답 패킷을 보내지 않으면 49001 포트는 더 이상 패킷을 받아들이지 않는다)

 

5. 만약 5초가 지난 후 WP 7.1 클라이언트에서 UDP 패킷을 전송하면, 새로운 로컬 포트가 바인딩된다.

위 예처럼 49001번 포트에서 패킷이 전송되고 5초가 지난 다음 UDP 패킷을 전송하면, 49002번 포트가 바인딩된다. 경우에 따라 49002번 포트가 아닌 다른 포트가 바인딩 될 수도 있지만, 하나의 앱에서 연속적으로 UDP 패킷을 전송할 경우에는 대부분 바로 다음 로컬 포트 번호가 바인딩된다.

 

6. 위 사항 이외에는 일반적인 UDP 패킷과 동일하게 동작한다.

이를테면 로컬 브로드캐스트 송신/수신 등도 정상적으로 동작한다. 문제는 포트 번호를 알 수 없기 때문에 모든 포트 번호에 일일이 UDP 패킷을 보내봐야 한다는 것이지만. (참고로, 내 맥북에어의 WP 에뮬레이터에서 49001~65535 포트에 udp 패킷을 전송하는데 약 27초가 걸렸다)

 

상술한 내용을 기반으로 WP 7.1 SDK에서의 UDP 통신을 위한 트릭을 하나 제시하자면;

WP 7.1 클라이언트가 4초마다 의미없는 UDP 패킷(1바이트짜리 패킷도 괜찮고, 수신하는 IP가 실제로 존재하지 않는 호스트라도 상관없다)을 전송하면서, UDP 서버에게 Alive 메시지를 전달하고 나면, UDP 서버가 다른 호스트들에게 해당 WP 7.1 클라이언트의 포트 번호를 알린다. 그러면 WP 7.1 클라이언트로부터 패킷을 수신한 UDP 서버가 아니더라도, WP 7.1 클라이언트의 로컬 포트 번호를 알고 있는 호스트는 자유롭게 WP 7.1 클라이언트에게 UDP 패킷을 전송할 수 있게 된다.

 

현재 BITNA의 WP 버전은 이 트릭을 사용하여 구현되어 있다. 이 BITNA 앱의 경우 결국은 각각의 기기들이 P2P 통신을 통해서 서로를 발견하고 메시지를 주고 받아야 하는데, 자신의 UDP 포트 번호조차 알 수 없는 환경이어서 여러모로 고심해야 했지만, 뭐 어떻게든 구현되었다. 결국은 Case by case의 문제다보니, 위의 사항들을 숙지하고 여러모로 고심해보면 답이 나오지 않을까, 마 그런 생각을 갖고 있습니다.

 

그럼, 윈도우 폰에서 UDP 소켓 통신을 시도해 보려는 개발자에게 도움이 되었기를 바라며 이만 총총.