Compartir a través de


Cómo conectarse con un socket de secuencias (HTML)

[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows en tiempo de ejecución. Si estás desarrollando para Windows 10, consulta la documentación más reciente

En este tema se muestra cómo habilitar una aplicación de Windows en tiempo de ejecución para enviar y recibir datos de red con un socket TCP mediante StreamSocket. Un socket TCP proporciona transferencias de datos de red de bajo nivel en cualquier dirección para conexiones de larga duración. Los sockets TCP son la característica subyacente que utilizan la mayoría de los protocolos de red que se usan en Internet.

El componente cliente de la muestra crea un socket TCP para establecer una conexión de red, usa el socket para enviar datos y a continuación cierra el socket. El componente servidor de la muestra crea un socket TCP para escuchar y aceptar conexiones de red, acepta conexiones del socket entrante, utiliza el socket para recibir datos del cliente y cierra el socket. Esta muestra se proporciona en los lenguajes de programación JavaScript, C#, VB y C++.

El componente cliente de la muestra demuestra las siguientes funciones:

  • Usa la clase StreamSocket para crear un socket TCP.
  • Establece una conexión de red con un servidor de red TCP mediante uno de los métodos StreamSocket.ConnectAsync.
  • Envía datos al servidor mediante el objeto Streams.DataWriter, que permite a un programador escribir tipos comunes (por ejemplo, enteros y cadenas) en cualquier secuencia.
  • Cierra el socket.

El componente servidor de la muestra demuestra las siguientes funciones:

Nota  Para utilizar esta muestra, se requiere acceso a la red mediante la interfaz de bucle invertido.

 

Requisitos previos

En los siguientes ejemplos, se usa JavaScript. Para obtener ayuda para crear tu primera aplicación, consulta Crear la primera aplicación de la Tienda Windows con JavaScript.

Para asegurarte de que la aplicación de la Tienda Windows está lista para la red, debes establecer la funcionalidad en el archivo Package.appxmanifest del proyecto. Para obtener una definición de cada funcionalidad de red, consulta el tema sobre el procedimiento para configurar las funcionalidades de aislamiento de red.

Instrucciones

Crear un nuevo proyecto

  1. Abre Microsoft Visual Studio 2013 y selecciona Nuevo proyecto en el menú Archivo.
  2. En la lista de plantillas, elige JavaScript.
  3. En la sección, elige Store apps.
  4. En la sección, selecciona Universal Apps, Windows apps, o Windows Phone apps (en función de la plataforma de destino) y, luego, selecciona Aplicación vacía.
  5. Asigna el nombre socketsSample a la aplicación y haz clic en Aceptar.

Establecer funcionalidades para habilitar el acceso a la red

Tienes que establecer las funcionalidades de red de tu aplicación si esta necesita acceso a la red. Una aplicación que utiliza un StreamSocket para conectarse a un servicio de red necesita que se hayan establecido las funcionalidades de red.

Si la aplicación necesita conectarse a servicios remotos de Internet como cliente, establece la funcionalidad Internet (cliente). Si la aplicación necesita poder conectarse como cliente a servicios remotos en una red doméstica o de trabajo, se necesita la funcionalidad Redes privadas (cliente y servidor).

Si la aplicación necesita utilizar el StreamSocketListener para escuchar las conexiones entrantes de extremos remotos en Internet, se necesita la funcionalidad Internet (cliente y servidor). Si la aplicación necesita utilizar el StreamSocketListener para escuchar las conexiones entrantes de extremos remotos en una red doméstica o de trabajo, se necesita la funcionalidad Redes privadas (cliente y servidor).

Nota  En Windows Phone, solo hay una funcionalidad de red Internet (cliente y servidor) que habilita todo el acceso a la red para la aplicación.

 

Si el componente servidor de esta muestra que escucha las conexiones entrantes se ejecuta en el mismo dispositivo que el componente cliente, sería necesario acceso de bucle invertido. Las aplicaciones que se desarrollen y se ejecuten en Visual Studio 2013 se registrarán automáticamente como exentas de las restricciones de bucle invertido. Para obtener más información, consulta Cómo habilitar el aislamiento de red de bucle invertido y de depuración.

Si quieres obtener información más detallada acerca del acceso de red, consulta Cómo configurar las funcionalidades de aislamiento de red.

Estos pasos son necesarios para establecer las funcionalidades de red de una aplicación antes de que se implemente y si la aplicación accede a un servicio de red en Internet o en una red doméstica o de trabajo.

  1. Abre Microsoft Visual Studio para abrir el archivo package.appxmanifest.

  2. Selecciona la pestaña Funcionalidad.

  3. Para compilar la versión para Windows de la muestra, selecciona las funcionalidades Internet (cliente) y Redes privadas (cliente y servidor).

    Para crear la versión para Windows Phone de la muestra, selecciona la funcionalidad Internet (cliente y servidor).

  4. Guarda y cierra el archivo de manifiesto.

Agregar HTML UI

  1. Abre la carpeta html. Abre un nuevo archivo startListener.html y agrega el siguiente código HTML en las secciones <head> y <body>

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script src="/js/socketsSample.js"></script>
        <script src="/js/startListener.js"></script>
    </head>
    <body>
        <div data-win-control="SdkSample.ScenarioInput">
            <p>
                StreamSocketListener will create the "server" side of a connection. It listens on
                a "service name" (often a port number) and calls a callback when it accepts a connection;
                this happens when some other application tries to connect. Once a connection is
                accepted, the acceptAsync() method needs to be called again.
            </p>
            <p>
                <label for="serviceNameAccept">Service Name:</label>
                <input id="serviceNameAccept" type="text" />
            </p>
            <p>
                <button id="buttonStartListener">Create StreamSocketListener and start to listen</button>
            </p>
        </div>
        <div data-win-control="SdkSample.ScenarioOutput">
            <p id="statusBox"></p>
            <p id="outputBox"></p>
        </div>
    </body>
    </html>
    

    .

  2. Abre la carpeta html. Abre un nuevo archivo connectToListener.html y agrega el siguiente código HTML en las secciones <head> y <body>

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script src="/js/connectToListener.js"></script>
    </head>
    <body>
        <div data-win-control="SdkSample.ScenarioInput">
            <p>
                Next, you need the "other side of the connection" -- you need to connect to a listener.
                The host name and service name (often a port number) to connect to are the "Host
                Name:" and "Service Name:" entries. The service name should match what you started
                to listen to!
            </p>
            <p>
                The connection will automatically use IPv6 as needed. It will also resolve international
                domain names.
            </p>
            <p>
                Due to the network security system, you cannot connect to other applications running
                on the same machine. This means that you can only use "localhost" to connect to
                the same application (specifically, you can connect to a listener on the same machine
                running in the same app container)
            </p>
            <p>
                <label for="hostNameConnect">Host Name:</label>
                <input id="hostNameConnect" type="text" />
            </p>
            <p>
                <label for="serviceNameConnect">Service Name:</label>
                <input id="serviceNameConnect" type="text" />
            </p>
            <p>
                <button id="buttonOpen">Connect Now</button>
            </p>
        </div>
        <div data-win-control="SdkSample.ScenarioOutput">
            <p id="statusBox"></p>
            <p id="outputBox"></p>
        </div>
    </body>
    </html>
    

    .

  3. Abre la carpeta html. Abre un nuevo archivo sendData.html y agrega el siguiente código HTML en las secciones <head> y <body>

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script src="/js/sendData.js"></script>
    </head>
    <body>
        <div data-win-control="SdkSample.ScenarioInput">
            <p>
                Now you can send data to the "server". Sending data is often done with the DataWriter
                object; it will write to the socket stream. You can also hook up the socket stream
                to other streams in Windows 8.
            </p>
            <p>
                <button id="buttonSend">Send 'hello' now</button>
            </p>
        </div>
        <div data-win-control="SdkSample.ScenarioOutput">
            <p id="statusBox"></p>
            <p id="outputBox"></p>
        </div>
    </body>
    </html>
    

    .

  4. Abre la carpeta html. Abre un nuevo archivo closeSocket.html y agrega el siguiente código HTML en las secciones <head> y <body>

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script src="/js/closeSocket.js"></script>
    </head>
    <body>
        <div data-win-control="SdkSample.ScenarioInput">
            <p>Lastly, you can close all sockets.</p>
            <p>If you don't close your socket, it will be closed for you when the application exits.</p>
            <p>
                <button id="buttonClose">Close all sockets</button>
            </p>
        </div>
        <div data-win-control="SdkSample.ScenarioOutput">
            <p id="statusBox"></p>
            <p id="outputBox"></p>
        </div>
    </body>
    </html>
    

    .

Definir el ejemplo y los escenarios

En este paso, el código define el ejemplo, los archivos HTML y los escenarios que se usan en el ejemplo. El código también agrega escuchas de eventos e inicia la aplicación. Las opciones de escenario permiten al usuario iniciar la escucha de socket, iniciar el cliente para conectarse a la escucha, hacer que el cliente envíe datos al servidor y cerrar los sockets.

  • Abre la carpeta js. Abre el archivo default.js y agrégale el siguiente código.

        var sampleTitle = "StreamSocket";
    
        var scenarios = [
            { url: "/html/startListener.html", title: "Start StreamSocketListener" },
            { url: "/html/connectToListener.html", title: "Connect to Listener" },
            { url: "/html/sendData.html", title: "Send Data" },
            { url: "/html/closeSocket.html", title: "Close Socket" }
        ];
    
        function activated(eventObject) {
            if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                // Use setPromise to indicate to the system that the splash screen must not be torn down
                // until after processAll and navigate complete asynchronously.
                eventObject.setPromise(WinJS.UI.processAll().then(function () {
                    // Navigate to either the first scenario or to the last running scenario
                    // before suspension or termination.
                    var url = WinJS.Application.sessionState.lastUrl || scenarios[0].url;
                    return WinJS.Navigation.navigate(url);
                }));
            }
        }
    
        WinJS.Navigation.addEventListener("navigated", function (eventObject) {
            var url = eventObject.detail.location;
            var host = document.getElementById("contentHost");
            // Call unload method on current scenario, if there is one
            host.winControl && host.winControl.unload && host.winControl.unload();
            WinJS.Utilities.empty(host);
            eventObject.detail.setPromise(WinJS.UI.Pages.render(url, host, eventObject.detail.state).then(function () {
                WinJS.Application.sessionState.lastUrl = url;
            }));
        });
    
        WinJS.Namespace.define("SdkSample", {
            sampleTitle: sampleTitle,
            scenarios: scenarios
        });
    
        WinJS.Application.addEventListener("activated", activated, false);
        WinJS.Application.start();
    

Definir variables para funciones de eventos y sockets

En este paso, el código crea una serie de variables, incluidas el socket de escucha, el socket del cliente y el socket de lectura del servidor, y otras variables para errores y eventos. Las variables se crean para realizar un seguimiento del socket del cliente y saber si está en estado conectado o en proceso de cierre. Este paso también define el nombre de host y el nombre de servicio (puerto TCP) para conectarse al servidor. Los valores del nombre de host y nombre de servicio se establecen de manera predeterminada, pero pueden cambiarse en la interfaz de usuario.

  • Abre la carpeta js. Abre un nuevo archivo socketsSample.js y agrégale el siguiente código.

    var socketsSample = {};
    
    (function () {
        "use strict";
    
        socketsSample.listener = null; // A StreamSocketListener that acts as our server.
        socketsSample.serverSocket = null; // The server socket that's been accepted.
        socketsSample.serverReader = null; // The reader for the server socket.
        socketsSample.clientSocket = null; // The client socket that will connect to the server socket.
        socketsSample.connected = false;
        socketsSample.closing = false;
    
        socketsSample.serviceNameAccept = "22112";
        socketsSample.hostNameConnect = "localhost";
        socketsSample.serviceNameConnect = "22112";
    
        socketsSample.displayStatus = function (message) {
            document.getElementById("statusBox").innerHTML = message;
        };
    
        socketsSample.displayOutput = function (message) {
            document.getElementById("outputBox").innerHTML = message;
        };
    
        socketsSample.setValues = function () {
            var serviceNameAcceptInput = document.getElementById("serviceNameAccept");
            var hostNameConnectInput = document.getElementById("hostNameConnect");
            var serviceNameConnectInput = document.getElementById("serviceNameConnect");
    
            if (serviceNameAcceptInput) {
                serviceNameAcceptInput.value = socketsSample.serviceNameAccept;
            }
            if (hostNameConnectInput) {
                hostNameConnectInput.value = socketsSample.hostNameConnect;
            }
            if (serviceNameConnectInput) {
                serviceNameConnectInput.value = socketsSample.serviceNameConnect;
            }
        };
    
        socketsSample.getValues = function (evt) {
            switch (evt.target.id) {
                case "serviceNameAccept":
                    socketsSample.serviceNameAccept = evt.target.value;
                    break;
                case "hostNameConnect":
                    socketsSample.hostNameConnect = evt.target.value;
                    break;
                case "serviceNameConnect":
                    socketsSample.serviceNameConnect = evt.target.value;
                    break;
            }
        };
    })();
    

Crear una escucha e iniciarla en el nombre de servicio (puerto)

El código de esta sección crea una escucha y la inicia. También se agregan funciones para controlar eventos cuando el usuario solicite que la escucha se enlace a una dirección IP y puerto TCP, acepte una conexión y lea datos enviados desde el cliente.

Nota  Si bien en este ejemplo específico el cliente y el servidor están en la misma aplicación, normalmente podrías tener aplicaciones de cliente y de servidor independientes.

 

  • Abre la carpeta js. Abre un nuevo archivo startListener.js y agrégale el siguiente código:

        var page = WinJS.UI.Pages.define("/html/startListener.html", {
            ready: function (element, options) {
                document.getElementById("buttonStartListener").addEventListener("click", startListener, false);
                document.getElementById("serviceNameAccept").addEventListener("change", socketsSample.getValues, false);
                socketsSample.setValues();
            }
        });
    
        function startListener() {
            if (socketsSample.listener) {
                socketsSample.displayStatus("Already have a listener; call close to close the listener.");
                return;
            }
            socketsSample.closing = false;
            var serviceName = document.getElementById("serviceNameAccept").value;
            socketsSample.listener = new Windows.Networking.Sockets.StreamSocketListener(serviceName);
            socketsSample.listener.addEventListener("connectionreceived", onServerAccept);
            socketsSample.displayStatus("Server: listener creation started.");
            socketsSample.listener.bindServiceNameAsync(serviceName).done(function () {
                socketsSample.displayStatus("Server: listener creation completed.");
            }, onError);
        }
    
        // This has to be a real function ; it will "loop" back on itself with the
        // call to acceptAsync at the very end.
        function onServerAccept(eventArgument) {
            socketsSample.displayStatus("Server: connection accepted.");
            socketsSample.serverSocket = eventArgument.socket;
            socketsSample.serverReader = new Windows.Storage.Streams.DataReader(socketsSample.serverSocket.inputStream);
            startServerRead();
        }
    
        // The protocol here is simple: a four-byte 'network byte order' (big-endian) integer
        // that says how long a string is, and then a string that is that long.
        // We wait for exactly 4 bytes, read in the count value, and then wait for
        // count bytes, and then display them.
        function startServerRead() {
            socketsSample.serverReader.loadAsync(4).done(function (sizeBytesRead) {
                // Make sure 4 bytes were read.
                if (sizeBytesRead !== 4) {
                    socketsSample.displayStatus("Server: connection lost.");
                    return;
                }
    
                // Read in the 4 bytes count and then read in that many bytes.
                var count = socketsSample.serverReader.readInt32();
                return socketsSample.serverReader.loadAsync(count).then(function (stringBytesRead) {
                    // Make sure the whole string was read.
                    if (stringBytesRead !== count) {
                        socketsSample.displayStatus("Server: connection lost.");
                        return;
                    }
                    // Read in the string.
                    var string = socketsSample.serverReader.readString(count);
                    socketsSample.displayOutput("Server read: " + string);
                    // Restart the read for more bytes.
                    startServerRead();
                }); // End of "read in rest of string" function.
            }, onError);
        }
    
        function onError(reason) {
            // When we close a socket, outstanding async operations will be canceled and the
            // error callbacks called.  There's no point in displaying those errors.
            if (!socketsSample.closing) {
                socketsSample.displayStatus(reason);
            }
        }
    

Crear un socket y conectar con un extremo remoto

En este paso, el código agrega una función para crear el socket y conectar al extremo remoto, normalmente un servidor, mediante el método StreamSocket.ConnectAsync. También se agrega una función para controlar casos en los que se presente un error cuando el cliente intente establecer una conexión.

  • Abre la carpeta js. Abre un nuevo archivo connectToListener.js y agrégale el siguiente código:

        var page = WinJS.UI.Pages.define("/html/connectToListener.html", {
            ready: function (element, options) {
                document.getElementById("buttonOpen").addEventListener("click", openClient, false);
                document.getElementById("hostNameConnect").addEventListener("change", socketsSample.getValues, false);
                document.getElementById("serviceNameConnect").addEventListener("change", socketsSample.getValues, false);
                socketsSample.setValues();
            }
        });
    
        function openClient() {
            if (socketsSample.clientSocket) {
                socketsSample.displayStatus("Already have a client; call close to close the listener and the client.");
                return;
            }
            socketsSample.closing = false;
            var serverHostName = new Windows.Networking.HostName(document.getElementById("hostNameConnect").value);
            var serviceName = document.getElementById("serviceNameConnect").value;
            socketsSample.clientSocket = new Windows.Networking.Sockets.StreamSocket();
            socketsSample.displayStatus("Client: connection started.");
            socketsSample.clientSocket.connectAsync(serverHostName, serviceName).done(function () {
                socketsSample.displayStatus("Client: connection completed.");
                socketsSample.connected = true;
            }, onError);
        }
    
        function onError(reason) {
            socketsSample.clientSocket = null;
    
            // When we close a socket, outstanding async operations will be canceled and the
            // error callbacks called.  There's no point in displaying those errors.
            if (!socketsSample.closing) {
                socketsSample.displayStatus(reason);
            }
        }
    

Enviar y recibir datos del cliente

En este paso, el código agrega una función para enviar datos al servidor mediante los métodos de la clase Windows.Storage.Stream.DataWriter.

  • Abre la carpeta js. Abre un nuevo archivo sendData.js y agrégale el siguiente código:

        var page = WinJS.UI.Pages.define("/html/sendData.html", {
            ready: function (element, options) {
                document.getElementById("buttonSend").addEventListener("click", sendHello, false);
            }
        });
    
        function sendHello() {
            if (!socketsSample.connected) {
                socketsSample.displayStatus("Client: you must connect the client before using it.");
                return;
            }
            var writer = new Windows.Storage.Streams.DataWriter(socketsSample.clientSocket.outputStream);
            var string = "Hello World";
            var len = writer.measureString(string); // Gets the UTF-8 string length.
            writer.writeInt32(len);
            writer.writeString(string);
            socketsSample.displayStatus("Client sending: " + string + ".");
            writer.storeAsync().done(function () {
                socketsSample.displayStatus("Client sent: " + string + ".");
                writer.detachStream();
            }, onError);
        }
    
        function onError(reason) {
            // When we close a socket, outstanding async operations will be canceled and the
            // error callbacks called.  There's no point in displaying those errors.
            if (!socketsSample.closing) {
                socketsSample.displayStatus(reason);
            }
        }
    

Cerrar los sockets

En este paso, el código cerrará los sockets mediante el método StreamSocket.Close. Cuando los sockets se cierren, todas las operaciones pendientes terminarán y se llamarán a las rutinas de errores.

  • Abre la carpeta js. Abre un nuevo archivo socketClose.js y agrégale el siguiente código:

        var page = WinJS.UI.Pages.define("/html/closeSocket.html", {
            ready: function (element, options) {
                document.getElementById("buttonClose").addEventListener("click", closeListenerAndSockets, false);
            }
        });
    
        function closeListenerAndSockets() {
            socketsSample.closing = true;
            if (socketsSample.listener) {
                socketsSample.listener.close();
                socketsSample.listener = null;
            }
            if (socketsSample.serverSocket) {
                socketsSample.serverSocket.close();
                socketsSample.serverSocket = null;
            }
            if (socketsSample.clientSocket) {
                socketsSample.clientSocket.close();
                socketsSample.clientSocket = null;
                socketsSample.connected = false;
            }
            socketsSample.displayStatus("Client and server closed.");
        }
    

Ejecutar la aplicación

  • Para ejecutar la aplicación, presiona F5 en Visual Studio para que se ejecute el proyecto. Selecciona los botones para iniciar la escucha, conectar el cliente a la escucha, enviar datos y cerrar los sockets.

Resumen y siguientes pasos

En este tema, creaste una aplicación que usa un socket de secuencias TCP para establecer una conexión de red y enviar datos con un objeto StreamSocket. La aplicación también mostró cómo escuchar una conexión TCP y aceptar una conexión de un socket de secuencias que puede usarse para enviar y recibir datos.

El código fuente y los archivos de compilación de ese tema están disponibles como la muestra de StreamSocket.

También puedes usar un socket de datagramas para que una conexión de red envíe datos. Si quieres ver un ejemplo, consulta Cómo conectar con un socket de datagramas.

Temas relacionados

Otros recursos

Conexión con sockets

Cómo configurar las funcionalidades de red

Cómo conectar con un socket de datagramas

Cómo habilitar el aislamiento de red de bucle invertido y de depuración

Cómo proteger conexiones de sockets con TLS/SSL

Cómo establecer tiempos de espera en operaciones de socket

Cómo usar controles de sockets avanzados

Solución de problemas y conexiones de red de depuración

Referencia

StreamSocket

StreamSocketListener

Windows.Networking

Windows.Networking.Sockets

Windows.Storage.Stream.DataWriter

Muestras

Muestra de StreamSocket