Introduction
El cliente de ejemplo (que esta en sus correos) fue creado en C# por lo que el mismo tipo de funciones sirve para el cliente en Windows Mobile.
Details
El cliente (al ligual que el servidor) envia y recibe mensajes en XML, el formato de los mensajes XML es:
<?xml version="1.0" encoding="utf-8"?>
<Mensaje xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Tipo>TIPO_DEL_MENSAJE</Tipo>
<contenido>TEXTO_DEL_MENSAJE</contenido>
<clientID>ID_DEL_CLIENTE</clientID>
</Mensaje>Para esto se usa un método de Serialización de objetos a XMl en la clase Mensaje. Ej: Aqui se muestra código para crear un archivo XML para enviar
Mensaje mensaje = new Mensaje();
mensaje.id = ID_DEL CLIENTE; //este se obtiene del mensaje de bienvenida recibido desde el servidor
mensaje.tipo = Mensaje.type.LIST;
mensaje.contenido = "LIST";
mensaje.Serialize();
]]]
Este código crea un mensaje de comando LIST (solicita el listado de videos del servidor).
El método para recibir mensajes esta implementado:
{{{
private static byte[] Recibir(Socket s){
int total = 0;
int recv;
byte[] datasize = new byte[4];
recv = s.Receive(datasize, 0, 4, 0); /*Recibe el tamaño del archivo a recibir*/
int size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(datasize, 0));/*Convierte el array de bytes recibido a entero*/
int dataleft = size;
byte[] data = new byte[size]; /*Array de bytes donde guardar los datos del archivo a recibir*/
while (total < size)//Mientras no se termine de recibir todo
{
recv = s.Receive(data, total, dataleft, 0);/*Recibe guardando en data, con offset total (total recibido) y lo que se desea recibir (dataleft)*/
if (recv == 0)//Si ya se termino de leer todo.. se termina el bucle
{
break;
}
total += recv;
dataleft -= recv;
}
return data; //Se retorna el array de bytes para ser manipulado posteriormente
}
}}}
este método retorna un arreglo de bytes que debe ser transformado para escribirlo en un archivo.
En el código del cliente de ejemplo se muestra como convertir lo recibido en un objeto Mensaje (siempre y cuando lo recibido sea un archivo xml de formato mensaje)
{{{
byte[] recibido = Recibir(sender); //Recibe Bienvenida del servidor
Stream st = new MemoryStream(recibido); //deserializar el mensaje XML
Mensaje msg = Mensaje.Deserialize(st); // Ahora msg es un objeto que referencia los datos recibidos desde el servidor
}}}
Ahora para enviar un mensaje, por ejemplo LIST al servidor:
{{{
//Creando mensaje a enviar
Mensaje mensaje = new Mensaje();
mensaje.contenido = "VIDEO"; //id del video
mensaje.tipo = Mensaje.MsgType.LIST;
mensaje.clientID = msg.clientID;
mensaje.Serialize();//Serializar el mensaje, esto crea un archivo físico en formato XML
SendMsg(socket,mensaje);//Enviar mensaje al servidor
}}}
la Función para enviar un mensaje al servidor es *SendMsg* que se vale de *ReadFully* para leer el archivo.
{{{
private static byte[] ReadFully (Stream stream){
int initialLength = 1024;
byte[] buffer = new byte[initialLength];
int read=0;
int chunk;
while ( (chunk = stream.Read(buffer, read, buffer.Length-read)) > 0){
read += chunk;
if (read == buffer.Length){
int nextByte = stream.ReadByte();
if (nextByte==-1){
return buffer;
}
byte[] newBuffer = new byte[buffer.Length*2];
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read]=(byte)nextByte;
buffer = newBuffer;
read++;
}
}
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}
private static void SendMsg(Socket socket, Mensaje mensaje){
mensaje.Serialize();
FileStream fs = new FileStream(mensaje.getFile(),FileMode.Open,FileAccess.Read,FileShare.Read);
byte[] video = ReadFully(fs);
int total = 0;
int size = video.Length;
int dataleft = size;
int sent;
byte[] datasize = new byte[4];
datasize = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(size));
sent = socket.Send(datasize);
while(total < size){
sent = socket.Send(video,total,dataleft,SocketFlags.None);
total+= sent;
dataleft-= sent;
}
}
}}}
Finalmente el servidor esta configurado para que el cliente realice el siguiente funcionamiento, para realizar pruebas
Funcionamiento del cliente:
* Se conecta al servidor
* Recibe el mensaje del servidor
* Envia un mensaje LIST
* Recibe el listado de videos del servidor
* se desconecta.
En caso de enviar un mensaje LIST el cliente queda esperando un listado del servidor con cierto formato XML
este formato esta basado en el objeto *VideoList*, por lo que el cliente debe deserializarlo en un listado de tipos VideoList.
Clase videolist
{{{
[XmlRoot("Listado")]
public class VideoList
{
[XmlElement("Titulo")]
public String titulo;
[XmlEnum("Duracion")]
public String duracion;
[XmlElement("id")]
public int id;
[XmlElement("Imagen")]
public String codigo_imagen;
[XmlElement("Path")]
public String path;
public VideoList ()
{
}
public void show(){
Console.WriteLine("Titulo: "+titulo);
Console.Write("\t Duracion: "+duracion+" | Id: "+id);
Console.WriteLine("\t Path: "+path);
}
}
}}}
Para esto el cliente debe tener una función para crear este listado de videos desde el archivo XML
{{{
private static List<VideoList> DeserializeList(String archivo, Guid id){
XmlSerializer deserializer = new XmlSerializer(typeof(List<VideoList>));
TextReader textReader = new StreamReader(archivo);
List<VideoList> listado = (List<VideoList>)deserializer.Deserialize(textReader);
textReader.Close();
return listado;
}
}}}
Esto genera un listado tipo List que debe ser recorrido con un foreach:
{{{
List<VideoList> listado = DeserializeList("/xml/listado.xml",msg.clientID);
foreach(VideoList video in listado){
video.show();
}
}}}
El metodo show muestra por consola los elementos del video _"de turno"_
Este listado es el que debe mostrarse en el cliente.
Por ahora el campo _imagen_ es solo para trabajos futuros