Broadcast mediante
UDP Fecha: 30/Abr/2005
(28/04/05)
|
Basándome en el artículo sobre Broadcast que publiqué para Visual Basic 6.0, decidí desarrollar uno igual para .NET. Esta versión del programa utiliza la clase Socket de System.Net.Sockets e hilos de ejecución. Programé este ejemplo utilizando la Beta 2 de Visual Basic .NET y C# 2005 (Whidbey).
Funcionamiento:
El programa consiste en un Socket que va a enviar un paquete de datos (texto) a la dirección Broadcast de toda la red local (System.Net.IPAddress.Broadcast) mediante un puerto determinado (en el ejemplo: 20145) y haciendo uso del protocolo UDP. Para recibir datos entrantes vamos a crear un hilo que se encargará de recepcionarlos mediante el método "ReceiveFrom" y un bucle que terminará al finalizar la aplicación. Una instancia del programa será capaz de enviar y recibir mensajes públicos desde cualquier computadora conectada a la red.
Creamos un nuevo proyecto y diseñaremos un formulario similar a la siguiente figura:
Modelo del formulario para la aplicación
Nombres de los controles:
txtMensaje: Contiene el mensaje que se desea enviar.
Código del formulario para Visual Basic .NET:
cmdEnviar: Al hacer clic en este botón, el mensaje se envía a toda la red.
txtDatosRecibidos: Todos los mensajes enviados desde otras PCs se mostrarán en esta caja de texto. Debe ser multilínea y con la propiedad ReadOnly a True.Imports System.Net Imports System.Net.Sockets Imports System.Text Imports System.Threading Public Class frmMain #Region "Variables" 'Variable de objeto que contiene el socket Dim ElSocket As New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) 'Variable que contiene al hilo encargado de recibir los datos Dim HiloRecibir As Thread 'Variable que indica si el programa se está cerrando Dim Saliendo As Boolean = False 'Variables temporales para almacenar los datos recibidos Dim DireccIP As String, ContenidoMensaje As String #End Region Private Sub txtMensaje_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtMensaje.TextChanged 'Cuando txtMensaje esté vacío, deshabilitar el botón de envío. cmdEnviar.Enabled = (txtMensaje.TextLength > 0) End Sub Private Sub cmdEnviar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdEnviar.Click 'Contiene la dirección de Broadcast y el puerto utilizado Dim DirecciónDestino As New IPEndPoint(IPAddress.Broadcast, 20145) 'Buffer que guardará los datos hasta que se envíen Dim DatosBytes As Byte() = Encoding.Default.GetBytes(txtMensaje.Text) 'Envía los datos ElSocket.SendTo(DatosBytes, DatosBytes.Length, SocketFlags.None, DirecciónDestino) txtMensaje.Clear() 'Limpia txtMensaje txtMensaje.Focus() 'Mueve el foco hacia txtMensaje End Sub Private Sub frmMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing Saliendo = True 'Indica que se está saliendo del programa ElSocket.Close() 'Cierra el socket HiloRecibir.Abort() 'Termina el proceso del hilo End Sub Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 'Separamos el puerto 200145 para usarlo en nuestra aplicación ElSocket.Bind(New IPEndPoint(IPAddress.Any, 20145)) 'Habilitamos la opción Broadcast para el socket ElSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, True) HiloRecibir = New Thread(AddressOf RecibirDatos) 'Crea el hilo HiloRecibir.Start() 'Inicia el hilo End Sub Private Sub RecibirDatos() 'Mientras el inidicador de salida no sea verdadero Do Until Saliendo 'Variable para obtener la IP de la máquína remitente Dim LaIPRemota As New IPEndPoint(IPAddress.Any, 0) 'Variable para almacenar la IP temporalmente Dim IPRecibida As EndPoint = CType(LaIPRemota, EndPoint) Dim RecibirBytes(255) As Byte 'Buffer Dim Datos As String = "" 'Texto a mostrar Try 'Recibe los datos ElSocket.ReceiveFrom(RecibirBytes, RecibirBytes.Length, SocketFlags.None, IPRecibida) 'Los convierte y lo guarda en la variable Datos Datos = Encoding.Default.GetString(RecibirBytes) Catch ex As SocketException If ex.ErrorCode = 10040 Then 'Datos muy largos Datos &= "[truncado]" 'Añade la cadena "[truncado]" al texto recibido Else 'Muestra el mensaje de error MsgBox("Error '" & ex.ErrorCode.ToString & "' " & ex.Message, MsgBoxStyle.Critical, "Error al recibir datos") End If End Try 'Convierte el tipo EndPoint a IPEndPoint con sus respectivas variables LaIPRemota = CType(IPRecibida, IPEndPoint) 'Guarda los datos en variables temporales DireccIP = LaIPRemota.Address.ToString ContenidoMensaje = Datos.ToString 'Invoca al evento que mostrará los datos en txtDatosRecibidos txtDatosRecibidos.Invoke(New EventHandler(AddressOf ActualizarTextoMensaje)) Loop End Sub Private Sub txtDatosRecibidos_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtDatosRecibidos.TextChanged 'Mostrar siempre la última línea del TextBox. txtDatosRecibidos.SelectionStart = txtDatosRecibidos.TextLength txtDatosRecibidos.ScrollToCaret() End Sub Protected Sub ActualizarTextoMensaje(ByVal sender As Object, ByVal e As System.EventArgs) 'Si txtDatosRecibidos está vacío: If txtDatosRecibidos.TextLength = 0 Then txtDatosRecibidos.Text = DireccIP & ">" & ContenidoMensaje Else 'de lo contrario insertar primero un salto de línea y luego los datos. txtDatosRecibidos.Text &= vbCrLf & DireccIP & ">" & ContenidoMensaje End If End Sub End ClassCódigo del formulario para Visual C#:
using System; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; namespace Broadcast_utilizando_UDP { public partial class frmMain : Form { #region "Variables" //Variable de objeto que contiene el socket Socket ElSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //Variable que contiene al hilo encargado de recibir los datos Thread HiloRecibir; //Variable que indica si el programa se está cerrando bool Saliendo = false; //Variables temporales para almacenar los datos recibidos string DireccIP; string ContenidoMensaje; #endregion public frmMain() { InitializeComponent(); } private void txtMensaje_TextChanged(object sender, EventArgs e) { //Cuando txtMensaje esté vacío, deshabilitar el botón de envío. cmdEnviar.Enabled = (txtMensaje.TextLength > 0); } private void cmdEnviar_Click(object sender, EventArgs e) { //Contiene la dirección de Broadcast y el puerto utilizado IPEndPoint DirecciónDestino = new IPEndPoint(IPAddress.Broadcast, 20145); //Buffer que guardará los datos hasta que se envíen byte[] DatosBytes = Encoding.Default.GetBytes(txtMensaje.Text); //Envía los datos ElSocket.SendTo(DatosBytes, DatosBytes.Length, SocketFlags.None, DirecciónDestino); txtMensaje.Clear(); //Limpia txtMensaje txtMensaje.Focus(); //Mueve el foco hacia txtMensaje } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) { Saliendo = true; //Indica que se está saliendo del programa ElSocket.Close(); //Cierra el socket HiloRecibir.Abort(); //Termina el proceso del hilo } private void frmMain_Load(object sender, EventArgs e) { //Separamos el puerto 200145 para usarlo en nuestra aplicación ElSocket.Bind(new IPEndPoint(IPAddress.Any, 20145)); //Habilitamos la opción Broadcast para el socket ElSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); HiloRecibir = new Thread(RecibirDatos); //Crea el hilo HiloRecibir.Start(); //Inicia el hilo } private void RecibirDatos() { //Mientras el inidicador de salida no sea verdadero while(!Saliendo){ //Variable para obtener la IP de la máquína remitente IPEndPoint LaIPRemota = new IPEndPoint(IPAddress.Any, 0); //Variable para almacenar la IP temporalmente EndPoint IPRecibida = (EndPoint)LaIPRemota; byte[] RecibirBytes = new byte[256]; //Buffer string Datos = ""; //Texto a mostrar try{ //Recibe los datos ElSocket.ReceiveFrom(RecibirBytes, RecibirBytes.Length, SocketFlags.None, ref IPRecibida); //Los convierte y lo guarda en la variable Datos Datos = Encoding.Default.GetString(RecibirBytes); }catch (SocketException ex){ if(ex.ErrorCode == 10040){ //Datos muy largos Datos += "[truncado]"; //Añade la cadena "[truncado]" al texto recibido }else{ //Muestra el mensaje de error MessageBox.Show("Error '" + ex.ErrorCode + "' " + ex.Message,"Error al recibir los datos", MessageBoxButtons.OK,MessageBoxIcon.Error); } } //Convierte el tipo EndPoint a IPEndPoint con sus respectivas variables LaIPRemota = (IPEndPoint)IPRecibida; //Guarda los datos en variables temporales DireccIP = LaIPRemota.Address.ToString(); ContenidoMensaje = Datos.ToString(); //Invoca al evento que mostrará los datos en txtDatosRecibidos txtDatosRecibidos.Invoke(new EventHandler(ActualizarTextoMensaje)); } } private void txtDatosRecibidos_TextChanged(object sender, EventArgs e) { //Mostrar siempre la última línea del TextBox. txtDatosRecibidos.SelectionStart = txtDatosRecibidos.TextLength; txtDatosRecibidos.ScrollToCaret(); } protected void ActualizarTextoMensaje(object sender, EventArgs e) { //Si txtDatosRecibidos está vacío: if(txtDatosRecibidos.TextLength == 0){ txtDatosRecibidos.Text = DireccIP + ">" + ContenidoMensaje; }else{ //de lo contrario insertar primero un salto de línea y luego los datos. txtDatosRecibidos.Text += "\r\n" + DireccIP + ">" + ContenidoMensaje; } } } }
Espacios de nombres usados en el código de este artículo:
System.Net
System.Net.Sockets
System.Text
System.Threading
Fichero con el código de ejemplo para VB .NET: galegre_BroadcastUDPvbnet.zip - Tamaño 18.4 KB
Fichero con el código de ejemplo para Visual C#: galegre_BroadcastUDPcs.zip - Tamaño 14.8 KB