SocketsFlash Player 9 y posterior, Adobe AIR 1.0 y posterior Un socket es un tipo de conexión de red establecida entre dos procesos de ordenadores. Normalmente, los procesos se ejecutan en dos equipos distintos conectados a la misma red de Protocolo de Internet (IP). Sin embargo, los procesos conectados se pueden ejecutar en el mismo equipo si se utiliza una dirección IP especial “local host”. Adobe Flash Player admite sockets de protocolo de control de transporte (TCP). Una aplicación de Flash Player se puede conectar a otro proceso que actúe como servidor de socket, pero no puede aceptar solicitudes de conexión entrantes de otros procesos. Dicho de otro modo, una aplicación de Flash Player se puede conectar a un servidor TCP, pero no puede hacer de servidor. La API de Flash Player también contiene la clase XMLSocket. La clase XMLSocket utiliza un protocolo específico de Flash Player que permite intercambiar mensajes XML con un servidor que comprenda dicho protocolo. La clase XMLSocket se introdujo en ActionScript 1 y sigue admitiéndose para tener compatibilidad con versiones anteriores. En general, la clase Socket debe utilizarse para nuevas aplicaciones a no ser que se esté conectando a un servidor creado específicamente para comunicarse con XMLSockets de Flash. Adobe AIR añade varias clases adicionales para programación de redes basadas en sockets. Las aplicaciones de AIR pueden actuar como servidores de socket TCP con la clase ServerSocket y pueden conectarse a servidores de socket que requieran seguridad SSL o TLS con la clase SecureSocket. Las aplicaciones de AIR también pueden enviar y recibir mensajes de protocolo de datagrama universal (UDP) con la clase DatagramSocket. Sockets TCPEl protocolo TCP (Transmission Control Protocol) proporciona un modo de intercambiar mensajes a través de una conexión de red permanente. TCP garantiza que los mensajes enviados llegan en el orden adecuado (siempre y cuando no haya serios problemas de red). Las conexiones TCP requieren un “cliente” y un “servidor”. Flash Player puede crear sockets de cliente. Adobe AIR puede, además, crear sockets de servidor. Las siguientes API de ActionScript proporcionan conexiones TCP:
Sockets de cliente binariosUna conexión de socket binario es similar a un socket XML, pero el cliente y el servidor no necesitan intercambiar mensajes XML. En lugar de eso, la conexión puede transferir datos como información binaria. Esto permite conectar una amplia gama de servicios, como servidores de correo (POP3, SMTP e IMAP) y servidores de noticias (NNTP). Clase SocketLa clase Socket, introducida en ActionScript, permite que el código ActionScript realice conexiones de socket, y que lea y escriba datos binarios sin formato. La clase Socket resulta útil para interactuar con servidores que utilicen protocolos binarios. Se pueden utilizar conexiones de socket binario para escribir código que permita la interacción con varios protocolos de Internet distintos, como POP3, SMTP, IMAP y NNTP. Esto, a su vez, permite a las aplicaciones conectarse a servidores de correos y noticias. Flash Player puede interactuar con un servidor directamente mediante el protocolo binario de dicho servidor. Algunos servidores utilizan el orden de bytes big-endian y otros emplean little-endian. La mayoría de los servidores de Internet utilizan big-endian, ya que es el "orden de bytes de la red". El orden de bytes littleEndian es popular porque la arquitectura Intel® x86 lo utiliza. Debe utilizarse el orden de bytes Endian que coincida con el orden de bytes del servidor que envía o recibe los datos. Todas las operaciones que se realizan mediante las interfaces IDataInput e IDataOutput, y las clases que implementan dichas interfaces (ByteArray, Socket y URLStream) se codifican de forma predeterminada en formato bigEndian. Esto supone que el byte más significativo va primero. El orden de bytes predeterminado se elige para que coincida con el de Java y con el orden de bytes de red oficial. Para cambiar entre el uso de orden de bytes bigEndian o littleEndian, se puede establecer la propiedad endian en Endian.BIG_ENDIAN o Endian.LITTLE_ENDIAN. La clase Socket hereda todos los métodos definidos por las interfaces IDataInput e IDataOutput (ubicadas en el paquete flash.utils). Estos métodos se deben utilizar para escribir y leer desde el socket.Para obtener más información, consulte: Sockets de cliente seguros (AIR)La clase SecureSocket se puede utilizar para conectarse a los servidores socket que utilicen la versión 4 de Secure Sockets Layer (SSLv4) o Transport Layer Security, versión 1 (TLSv1). Un socket seguro ofrece tres ventajas: autenticación del servidor, integridad de los datos y confidencialidad de los mensajes. El motor de ejecución de autentica un servidor utilizando el certificado del servidor y su relación con los certificados raíz o intermedios de la entidad emisora de certificados en el almacén de confianza del usuario. El motor de ejecución se basa en los algoritmos de criptografía utilizados por las implementaciones de protocolo SSL y TLS para proporcionar integridad de los datos y confidencialidad de los mensajes. Cuando se realiza la conexión a un servidor utilizando el objeto SecureSocket, el motor de ejecución valida el certificado del servidor utilizando el almacén de confianza del certificado. En Windows y Mac, el sistema operativo proporciona el almacén de confianza. En Linux, el motor de ejecución de proporciona su propio almacén de confianza. Si el certificado del servidor no es válido ni de confianza, el motor de ejecución distribuye un evento ioError. Se puede comprobar la propiedad serverCertificateStatus del objeto SecureSocket para determinar por qué se ha producido un error de validación. No existen previsiones para la comunicación con un servidor que no disponga de un certificado de confianza válido. La clase CertificateStatus define constantes de cadena que representan los posibles resultados de validación:
La comunicación con un objeto SecureSocket requiere que el servidor utilice un protocolo seguro y cuente con un certificado válido y de confianza. En otros aspectos, el uso de un objeto SecureSocket es el mismo que la utilización de un objeto Socket. El objeto SecureSocket no se admite en todas las plataformas. Utilice la propiedad isSupported de la clase SecureSocket para comprobar si el motor de ejecución admite el uso del objeto SecureSocket en el equipo cliente actual. Para obtener más información, consulte: Ejemplo de socket TCP: Creación de un cliente TelnetEn el ejemplo de Telnet se muestran las técnicas para conectar con un servidor remoto y transmitir datos con la clase Socket. El ejemplo ilustra las técnicas siguientes:
Para obtener los archivos de la aplicación de este ejemplo, consulte www.adobe.com/go/learn_programmingAS3samples_flash_es. Los archivos de la aplicación Telnet se encuentran en la carpeta Samples/Telnet. La aplicación consta de los siguientes archivos:
Información general de la aplicación de socket TelnetEl archivo principal TelnetSocket.mxml es responsable de crear la interfaz de usuario de toda la aplicación. Además de la interfaz de usuario, este archivo también define dos métodos, login() y sendCommand(), para conectar el usuario al servidor especificado. A continuación se muestra el código ActionScript del archivo de la aplicación principal: import com.example.programmingas3.socket.Telnet;
private var telnetClient:Telnet;
private function connect():void
{
telnetClient = new Telnet(serverName.text, int(portNumber.text), output);
console.title = "Connecting to " + serverName.text + ":" + portNumber.text;
console.enabled = true;
}
private function sendCommand():void
{
var ba:ByteArray = new ByteArray();
ba.writeMultiByte(command.text + "\n", "UTF-8");
telnetClient.writeBytesToSocket(ba);
command.text = "";
}
La primera línea de código importa la clase Telnet del paquete com.example.programmingas.socket personalizado. La segunda línea de código declara una instancia de la clase Telnet, telnetClient, que se inicializará posteriormente mediante el método connect(). A continuación, se declara el método connect() e inicializa la variable telnetClient declarada previamente. Este método pasa el nombre del servidor Telnet especificado por el usuario, el puerto del servidor Telnet y una referencia a un componente TextArea de la lista de visualización, que se utiliza para mostrar las respuestas de texto del servidor de socket. Las dos últimas líneas del método connect() establecen la propiedad title de Panel y activan el componente Panel, que permite al usuario enviar datos al servidor remoto. El método final del archivo principal de la aplicación, sendCommand(), se utiliza para enviar los comandos del usuario al servidor remoto como un objeto ByteArray. Información general de la clase TelnetLa clase Telnet es la responsable de conectar con el servidor Telnet remoto, y de enviar y recibir datos. La clase Telnet declara las siguientes variables privadas: private var serverURL:String; private var portNumber:int; private var socket:Socket; private var ta:TextArea; private var state:int = 0; La primera variable, serverURL, contiene la dirección del servidor, especificada por el usuario, con la que se va a conectar. La segunda variable, portNumber, es el número de puerto en el que se está ejecutando el servidor Telnet. De forma predeterminada, el servicio Telnet se ejecuta en el puerto 23. La tercera variable, socket, es una instancia de Socket que intentará conectar con el servidor definido por las variables serverURL y portNumber. La cuarta variable, ta, es una referencia a una instancia del componente TextArea en el escenario. Este componente se utiliza para mostrar las respuestas del servidor Telnet remoto o cualquier posible mensaje de error. La última variable, state, es un valor numérico que se utiliza para determinar las opciones que admite el cliente Telnet. Tal y como se ha visto previamente, se llama a la función constructora de la clase Telnet a través del método connect() en el archivo de la aplicación principal. El constructor Telnet adopta tres parámetros: server, port y output. Los parámetros server y port especifican el nombre de servidor y el número de puerto donde se ejecuta el servidor Telnet. El parámetro final, output, es una referencia a una instancia del componente TextArea en el escenario, donde los usuarios verán la salida del servidor. public function Telnet(server:String, port:int, output:TextArea)
{
serverURL = server;
portNumber = port;
ta = output;
socket = new Socket();
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(Event.CLOSE, closeHandler);
socket.addEventListener(ErrorEvent.ERROR, errorHandler);
socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
socket.addEventListener(ProgressEvent.SOCKET_DATA, dataHandler);
Security.loadPolicyFile("http://" + serverURL + "/crossdomain.xml");
try
{
msg("Trying to connect to " + serverURL + ":" + portNumber + "\n");
socket.connect(serverURL, portNumber);
}
catch (error:Error)
{
msg(error.message + "\n");
socket.close();
}
}
Escritura de datos en un socketPara escribir datos en una conexión de socket, es necesario llamar a cualquiera de los métodos de la clase Socket. Entre estos métodos de escritura se incluyen writeBoolean(), writeByte(), writeBytes() y writeDouble(), entre otros. Posteriormente, vacíe los datos en el búfer de salida con el método flush(). En el servidor Telnet, los datos se escriben en la conexión de socket mediante el método writeBytes(), que utiliza el conjunto de bytes como parámetro y lo envía al búfer de salida. La sintaxis del método writeBytesToSocket() es la siguiente: public function writeBytesToSocket(ba:ByteArray):void
{
socket.writeBytes(ba);
socket.flush();
}
Este método se llama mediante el método sendCommand() del archivo de la aplicación principal. Visualización de mensajes del servidor de socketCuando se recibe un mensaje del servidor de socket o se produce un evento, se llama al método personalizado msg(). Este método añade una cadena a TextArea en el escenario y llama a un método personalizado setScroll(), que desplaza el componente TextArea hasta la parte más baja. La sintaxis del método msg() es la siguiente: private function msg(value:String):void
{
ta.text += value;
setScroll();
}
Si el contenido del componente TextArea no se desplaza automáticamente, el usuario deberá arrastrar manualmente las barras de desplazamiento en el área de texto para ver la última respuesta del servidor. Desplazamiento de un componente TextAreaEl método setScroll() contiene una sola línea de código ActionScript que desplaza verticalmente el contenido del componente TextArea para que el usuario pueda ver la última línea del texto devuelto. El siguiente fragmento de código muestra el método setScroll(): public function setScroll():void
{
ta.verticalScrollPosition = ta.maxVerticalScrollPosition;
}
Este método establece la propiedad verticalScrollPosition, que es el número de línea de la fila superior de caracteres que se visualiza, con el valor de la propiedad maxVerticalScrollPosition. Sockets XMLUn socket XML permite crear una conexión en un servidor remoto que permanece abierta hasta que se cierra explícitamente. Puede intercambiar datos de cadenas, como XML, entre el servidor y el cliente. Una ventaja de utilizar un servidor de socket XML es que el usuario no tiene que solicitar datos de forma explícita. El servidor envía datos sin esperar una solicitud, y puede enviar datos a cualquier cliente conectado. En Flash Player y en contenido de Adobe AIR fuera del entorno limitado de la aplicación, las conexiones de socket XML requieren la presencia de un archivo de política de socket en el servidor de destino. Para obtener más información, consulte Controles de sitio web (archivos de política) y Conexión a sockets. La clase XMLSocket no puede atravesar cortafuegos automáticamente, ya que, a diferencia del protocolo RTMP (Real-Time Messaging Protocol), XMLSocket no dispone de prestaciones de tunelación HTTP. Si es necesario utilizar tunelación HTTP, debe considerarse la posibilidad de utilizar Flash Remoting o Flash Media Server (que admite RTMP). Las siguientes restricciones afectan a la forma y el lugar en que el contenido de Flash Player o de una aplicación de AIR puede utilizar un objeto XMLSocket para conectarse con el servidor fuera del entorno limitado de seguridad de la aplicación:
Nota: la configuración de un servidor para que se comunique con el objeto XMLSocket puede resultar compleja. Si la aplicación no requiere interactividad en tiempo real, utilice la clase URLLoader en vez de la clase XMLSocket.
Puede utilizar los métodos XMLSocket.connect() y XMLSocket.send() de la clase XMLSocket para transferir XML desde y hacia un servidor a través de una conexión de socket. El método XMLSocket.connect() establece una conexión de socket con un puerto de servidor web. El método XMLSocket.end() pasa un objeto XML al servidor especificado en la conexión de socket. Cuando se invoca el método XMLSocket.connect(), la aplicación abre una conexión TCP/IP con el servidor y la mantiene abierta hasta que produce una de las condiciones que se indican a continuación:
Conexión con un servidor con la clase XMLSocketPara crear una conexión de socket debe crear una aplicación de servidor que espere la petición de conexión de socket y envíe una respuesta a Flash Player o a la aplicación de AIR. Este tipo de aplicación de servidor puede escribirse en AIR o en un lenguaje de programación como Java, Python o Perl. Para utilizar la clase XMLSocket, el equipo servidor debe ejecutar un dominio que entienda el protocolo simple utilizado por la clase XMLSocket:
Creación y conexión de un servidor de socket XML de JavaEl siguiente código muestra un sencillo servidor XMLSocket escrito en Java que acepta conexiones entrantes y muestra los mensajes recibidos en la ventana de símbolo del sistema. De forma predeterminada, se crea un nuevo servidor en el puerto 8080 del equipo local, aunque se puede especificar otro número de puerto cuando se inicia el servidor desde la línea de comandos. Cree un nuevo documento de texto y añada el siguiente código: import java.io.*;
import java.net.*;
class SimpleServer
{
private static SimpleServer server;
ServerSocket socket;
Socket incoming;
BufferedReader readerIn;
PrintStream printOut;
public static void main(String[] args)
{
int port = 8080;
try
{
port = Integer.parseInt(args[0]);
}
catch (ArrayIndexOutOfBoundsException e)
{
// Catch exception and keep going.
}
server = new SimpleServer(port);
}
private SimpleServer(int port)
{
System.out.println(">> Starting SimpleServer");
try
{
socket = new ServerSocket(port);
incoming = socket.accept();
readerIn = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
printOut = new PrintStream(incoming.getOutputStream());
printOut.println("Enter EXIT to exit.\r");
out("Enter EXIT to exit.\r");
boolean done = false;
while (!done)
{
String str = readerIn.readLine();
if (str == null)
{
done = true;
}
else
{
out("Echo: " + str + "\r");
if(str.trim().equals("EXIT"))
{
done = true;
}
}
incoming.close();
}
}
catch (Exception e)
{
System.out.println(e);
}
}
private void out(String str)
{
printOut.println(str);
System.out.println(str);
}
}
Guarde el documento en el disco duro como SimpleServer.java y compílelo con la ayuda de un compilador de Java para crear un archivo de clase de Java denominado SimpleServer.class. Para iniciar el servidor XMLSocket, abra un símbolo del sistema y escriba java SimpleServer. El archivo SimpleServer.class puede almacenarse en cualquier lugar del equipo local o la red; no es necesario que esté en el directorio raíz del servidor web. Si no puede iniciar el servidor porque los archivos no se encuentran en la ruta de clases de Java, intente iniciar el servidor con java -classpath. SimpleServer.Para conectarse a XMLSocket desde la aplicación , es necesario crear una nueva instancia de la clase XMLSocket y llamar al método XMLSocket.connect(), pasando un nombre de host y un número de puerto, del siguiente modo: var xmlsock:XMLSocket = new XMLSocket();
xmlsock.connect("127.0.0.1", 8080);
Cuando se reciben datos del servidor, se distribuye el evento data (flash.events.DataEvent.DATA): xmlsock.addEventListener(DataEvent.DATA, onData);
private function onData(event:DataEvent):void
{
trace("[" + event.type + "] " + event.data);
}
Para enviar datos al servidor XMLSocket, se utiliza el método XMLSocket.send() y se pasa una cadena u objeto XML. Flash Player convierte el parámetro suministrado en un objeto String y envía el contenido al servidor XMLSocket, seguido de un byte cero (0): xmlsock.send(xmlFormattedData); El método XMLSocket.send() no devuelve ningún valor que indique si los datos se han transmitido correctamente. Si se produce un error al intentar enviar datos, se emite un error IOError. Cada mensaje que se envía al servidor de socket XML debe terminar con un carácter de nueva línea (\n).Para obtener más información, consulte XMLSocket. Sockets de servidorUtilice la clase ServerSocket para permitir que otro proceso se conecte a la aplicación utilizando un socket TCP (Transport Control Protocol). El proceso de conexión se puede ejecutar en el equipo local o en otro equipo conectado a la red. Cuando un objeto recibe una solicitud de conexión, distribuye un evento connect. El objeto ServerSocketConnectEvent distribuido con el evento contiene un objeto Socket. Este objeto Socket se puede emplear para una comunicación posterior con los demás procesos. Para detectar conexiones de socket entrantes:
El objeto ServerSocket sigue detectando conexiones adicionales hasta que se llama al método close(). En el siguiente ejemplo de código se muestra cómo crear una aplicación de servidor de socket. En el ejemplo se detectan las conexiones entrantes en el puerto 8087. Cuando se recibe una conexión, el ejemplo envía un mensaje (cadena “Connected.”) al socket de cliente. Por lo tanto, el servidor reproduce todos los mensajes recibidos del cliente. package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.ServerSocketConnectEvent;
import flash.net.ServerSocket;
import flash.net.Socket;
public class ServerSocketExample extends Sprite
{
private var serverSocket:ServerSocket;
private var clientSockets:Array = new Array();
public function ServerSocketExample()
{
try
{
// Create the server socket
serverSocket = new ServerSocket();
// Add the event listener
serverSocket.addEventListener( Event.CONNECT, connectHandler );
serverSocket.addEventListener( Event.CLOSE, onClose );
// Bind to local port 8087
serverSocket.bind( 8087, "127.0.0.1" );
// Listen for connections
serverSocket.listen();
trace( "Listening on " + serverSocket.localPort );
}
catch(e:SecurityError)
{
trace(e);
}
}
public function connectHandler(event:ServerSocketConnectEvent):void
{
//The socket is provided by the event object
var socket:Socket = event.socket as Socket;
clientSockets.push( socket );
socket.addEventListener( ProgressEvent.SOCKET_DATA, socketDataHandler);
socket.addEventListener( Event.CLOSE, onClientClose );
socket.addEventListener( IOErrorEvent.IO_ERROR, onIOError );
//Send a connect message
socket.writeUTFBytes("Connected.");
socket.flush();
trace( "Sending connect message" );
}
public function socketDataHandler(event:ProgressEvent):void
{
var socket:Socket = event.target as Socket
//Read the message from the socket
var message:String = socket.readUTFBytes( socket.bytesAvailable );
trace( "Received: " + message);
// Echo the received message back to the sender
message = "Echo -- " + message;
socket.writeUTFBytes( message );
socket.flush();
trace( "Sending: " + message );
}
private function onClientClose( event:Event ):void
{
trace( "Connection to client closed." );
//Should also remove from clientSockets array...
}
private function onIOError( errorEvent:IOErrorEvent ):void
{
trace( "IOError: " + errorEvent.text );
}
private function onClose( event:Event ):void
{
trace( "Server socket closed by OS." );
}
}}
Para obtener más información, consulte: Sockets UDP (AIR)El protocolo UDP (Universal Datagram Protocol) proporciona un modo de intercambiar mensajes a través de una conexión de red sin estado. UDP no garantiza que los mensajes se distribuyan en orden o incluso que los mensajes se envíen en modo alguno. Con UDP, el código de red del sistema operativo suele emplear menos tiempo en la identificación, seguimiento y reconocimiento de mensajes. De este modo, los mensajes UDP suelen llegar a la aplicación de destino con un retraso menor que los mensajes TCP. La comunicación del socket UDP resulta útil cuando se debe enviar información en tiempo real como, por ejemplo, actualizaciones de posición en un juego o paquetes de sonido en una aplicación de chat de audio. En estas aplicaciones, se tolera cierta pérdida de datos y una latencia de transmisión baja es más importante que la llegada garantizada. Para la mayoría de los demás objetivos, los sockets TCP representan un mejor opción. La aplicación de AIR puede enviar y recibir mensajes UDP con las clases DatagramSocket y DatagramSocketDataEvent. Para enviar o recibir un mensaje UDP:
El siguiente ejemplo de código muestra el modo en que una aplicación puede enviar y recibir mensajes UDP. El ejemplo envía un solo mensaje que contiene la cadena, “Hello.”, al equipo de destino. También realiza un seguimiento del contenido de todos los mensajes recibidos. package
{
import flash.display.Sprite;
import flash.events.DatagramSocketDataEvent;
import flash.events.Event;
import flash.net.DatagramSocket;
import flash.utils.ByteArray;
public class DatagramSocketExample extends Sprite
{
private var datagramSocket:DatagramSocket;
//The IP and port for this computer
private var localIP:String = "192.168.0.1";
private var localPort:int = 55555;
//The IP and port for the target computer
private var targetIP:String = "192.168.0.2";
private var targetPort:int = 55555;
public function DatagramSocketExample()
{
//Create the socket
datagramSocket = new DatagramSocket();
datagramSocket.addEventListener( DatagramSocketDataEvent.DATA, dataReceived );
//Bind the socket to the local network interface and port
datagramSocket.bind( localPort, localIP );
//Listen for incoming datagrams
datagramSocket.receive();
//Create a message in a ByteArray
var data:ByteArray = new ByteArray();
data.writeUTFBytes("Hello.");
//Send the datagram message
datagramSocket.send( data, 0, 0, targetIP, targetPort);
}
private function dataReceived( event:DatagramSocketDataEvent ):void
{
//Read the data from the datagram
trace("Received from " + event.srcAddress + ":" + event.srcPort + "> " +
event.data.readUTFBytes( event.data.bytesAvailable ) );
}
}}
Al emplear sockets UDP se debe tener en cuenta lo siguiente:
Para obtener más información, consulte: Direcciones IPv6Flash Player 9.0.115.0 y las versiones posteriores admiten IPv6 (Protocolo de Internet versión 6). IPv6 es una versión del Protocolo de Internet que admite direcciones de 128 bits (una mejora con respecto al protocolo anterior IPv4 que admite direcciones de 32 bits). Es posible que tenga que activar IPv6 en sus interfaces de red. Para más información, consulte la Ayuda del sistema operativo que aloja los datos. Si se admite IPv6 en el sistema de host, puede especificar direcciones literales numéricas de IPv6 en URL entre corchetes ([]), como se muestra a continuación: [2001:db8:ccc3:ffff:0:444d:555e:666f] Flash Player devuelve valores IPv6 literales, en función de las siguiente reglas:
Los valores IPv6 que devuelve Flash Player presentan las siguientes excepciones:
|
|