martes, 6 de diciembre de 2011

Broadcast en una LAN

Varias veces me he topado con tener que hacer un pequeño servicio de descubrimiento para localizar un servicio en una LAN. Siempre caigo en la trampa de enviar los datos a las dirección de broadcast predeterminada. Y en cada uno de los intentos el broadcast no se llevaba a cabo.

El siguiente ejemplo esta hecho para Android, pero la idea es la misma para todas las plataformas, obtener la dirección IP donde se esta ejecutando nuestra aplicación y la mascara de red, con esos datos se aplica un AND y vamos obteniendo byte a byte la dirección IP.

1:  DhcpInfo dhcp = wifi.getDhcpInfo();  
2:  int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;  
3:  byte[] ip = new byte[4];  
4:  for (int i = 0; i < 4; i++)  
5:    ip[i] = (byte) ((broadcast >> i * 8) & 0xFF);  



Otra metida de pata basten comun es usar el mismo puerto en el cliente y en el servidor, por lo que al hacer el broadcast detectamos que nos llegan datos al puerto donde estamos esperando la respuesta cuando en realidad es el mensaje que acabamos de difundir por la red.

sábado, 3 de diciembre de 2011

Permisos de acceso en hilos (.Net MF)

Trabajando para un proyecto de la universidad me toco implementar el refresco automático de la interfaz de usuario de la aplicación. Básicamente era llamar a un método que recogiera las medidas de los diferentes sensores conectados a una placa Tahoe II y actualizar los valores en pantalla. Hasta ahí todo bien, una tarea que a priori no debería llevar mucho tiempo.

Lo raro era que cuando la obtención de datos se hacia solo una vez funcionaba todo correctamente, pero al introducir el Timer para realizar la actualización cada 10 segundos, empezó a generarse el error InvalidOperationException. Mi primera reacción fue alguna condición de carrera estaba jodiendo todo, pero al mirar bien la documentación me di cuenta que no era eso. Sino que desde el Timer no se tenían los permisos de acceso adecuados para llamar a un objeto de otro Thread, en este caso el hilo principal.

Resulta que usar un Thread o un Timer fue una mala elección, en su lugar la mejor opcion es usar la clase DispatcherTimer, en la que los permisos de acceso son totalmente transparentes para el programador. Y todo el problema se reduce a las siguientes lineas

1:  refreshTimer = new DispatcherTimer(currentView.Dispatcher);  
2:  refreshTimer.Interval = new TimeSpan(0, 0, periodTime);  
3:  refreshTimer.Tick +=new EventHandler(refreshRoutine);  
4:  refreshTimer.Start();  

En este caso currentView es el objeto al que queremos acceder, y refreshRoutine es el método que queremos ejecutar para actualizar la pantalla.