Como se conectar com um soquete de fluxo (HTML)

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente]

Este tópico mostra como habilitar um aplicativo do Tempo de Execução do Windows para enviar e receber dados de rede com um soquete TCP usando um StreamSocket. Um soquete TCP fornece transferências de dados de rede em baixo nível em qualquer direção para conexões de longa duração. Soquetes TCP são o recurso subjacente usado pela maioria dos protocolos de rede disponíveis na Internet.

O componente cliente do exemplo cria um soquete TCP para estabelecer uma conexão de rede, usa esse soquete para enviar dados e fecha o soquete. O componente de servidor do exemplo cria um soquete TCP para ouvir e aceitar conexões de rede, aceita conexões do soquete de entrada, usa o soquete para receber dados do cliente e fecha o soquete. Este exemplo é fornecido nas linguagens de programação JavaScript, C#, VB e C++.

O componente cliente do exemplo demonstra os seguintes recursos:

  • Usar a classe StreamSocket para criar um soquete TCP.
  • Criar uma conexão de rede com um servidor de rede TCP usando um dos métodos StreamSocket.ConnectAsync.
  • Enviar dados ao servidor usando o objeto Streams.DataWriter, que permite que um programador escreva tipos comuns (inteiros e cadeias de caracteres, por exemplo) em qualquer fluxo.
  • Feche o soquete.

O componente de servidor do exemplo demonstra os seguintes recursos:

Observação  O uso deste exemplo requer o acesso à rede usando a interface de loopback.

 

Pré-requisitos

Os exemplos a seguir usam JavaScript. Para obter ajuda para criar o seu primeiro aplicativo, consulte Criar o seu primeiro aplicativo da Windows Store com JavaScript.

Para garantir que o aplicativo da Windows Store está pronto para rede, você deve definir a capacidade no arquivo Package.appxmanifest do projeto. Para obter uma definição de cada funcionalidade da, veja Como configurar funcionalidades de isolamento de rede.

Instruções

Criar um novo projeto

  1. Abra o Microsoft Visual Studio 2013 e selecione Novo Projeto no menu Arquivo.
  2. Na lista de modelos, selecione JavaScript.
  3. Na seção, escolha Store apps.
  4. Na seção, selecione Universal Apps, Windows apps ou Windows Phone apps (dependendo da plataforma que você deseja) e selecione Aplicativo em Branco.
  5. Nomeie o aplicativo socketsSample e clique em OK.

Definir as funcionalidades para permitir o acesso à rede

Você precisará definir recursos de rede para o seu aplicativo se o aplicativo precisar de acesso à rede. Um aplicativo que usa um StreamSocket para se conectar a um serviço de rede precisa de recursos de rede definidos.

Se o aplicativo precisa poder se conectar como um cliente aos serviços remotos na Internet, a capacidade Internet (Cliente) é necessária. Se o aplicativo precisa poder se conectar como um cliente a serviços remotos em uma rede doméstica ou corporativa, a funcionalidade Redes Privadas (Cliente e Servidor) é necessária.

Se o aplicativo precisa usar o StreamSocketListener para escutar conexões de entrada a partir de pontos de extremidade remotos na Internet, a funcionalidade Internet (Cliente e Servidor) é necessária. Se o aplicativo precisa usar o StreamSocketListener para escutar conexões de entrada a partir de pontos de extremidade remotos em uma rede doméstica ou corporativa, a funcionalidade Redes Privadas (Cliente e Servidor) é necessária.

Observação  No Windows Phone, existe apenas um recurso de rede Internet (Cliente e Servidor) que habilita todos os acessos de redes para o aplicativo.

 

Se o componente de servidor deste exemplo escutando conexões de entrada está sendo executado no mesmo dispositivo que o componente cliente, isso exige acesso loopback. Os aplicativos desenvolvidos e executados no Visual Studio 2013 serão registrados automaticamente como isentos das restrições de loopback. Para saber mais, consulte Como habilitar o loopback e depurar o isolamento da rede.

Para mais informações sobre acesso à rede, consulte Como configurar recursos de isolamento da rede.

Estas etapas são necessárias para definir os recursos de rede para um aplicativo antes de ele ser implantado ou se ele acessa um serviço de rede na Internet ou em uma rede doméstica ou corporativa.

  1. Use o Microsoft Visual Studio para abrir o arquivo package.appxmanifest.

  2. Selecione a guia Recursos.

  3. Para criar a versão de exemplo do Windows, selecione os recursos Internet (Cliente) e Redes Privadas (Cliente e Servidor).

    Para compilar a versão Windows Phone do exemplo, selecione a funcionalidade Internet (Cliente e Servidor).

  4. Salve e feche o arquivo de manifesto.

Adicionar a interface do usuário de HTML

  1. Abra a pasta html. Abra um novo arquivo startListener.html e adicione o HTML seguinte às seções <head> <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. Abra a pasta html. Abra um novo arquivo connectToListener.html e adicione o HTML seguinte às seções <head> <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. Abra a pasta html. Abra um novo arquivo sendData.html e adicione o seguinte HTML às seções <head> e <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. Abra a pasta html. Abra um novo arquivo closeSocket.html e adicione o HTML seguinte às seções <head> <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 o exemplo e os cenários

O código nesta etapa define o exemplo, os arquivos HTML e os cenários que são usados pela amostra. O código também adiciona ouvintes de eventos e inicia o aplicativo. As opções de cenários permitem que o usuário inicie o ouvinte de soquete, inicie o cliente para conectar ao ouvinte, faça com que o cliente envie alguns dados para o servidor e feche os soquetes.

  • Abra a pasta js. Abra o arquivo default.js e adicione o seguinte código a ele.

        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 variáveis para os soquetes e funções de evento

O código nesta etapa cria um número de variáveis incluindo o soquete de ouvinte, o soquete de cliente, o soquete de leitura de servidor e as várias variáveis para erros e eventos. As variáveis são criadas para acompanhar se o soquete de cliente está em um estado conectado ou fechando. Esta etapa também define o nome de host e nome do serviço (porta TCP) à qual conectar no servidor. O valor do nome de host e nome do serviço são definidos com um valor padrão que pode ser alterado na interface do usuário.

  • Abra a pasta js. Abra um novo arquivo socketsSample.js e adicione o código a seguir ao arquivo.

    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;
            }
        };
    })();
    

Criar um ouvinte e começar a ouvir um nome de serviço (porta)

O código nesta seção cria um ouvinte e inicia a audição. Há também funções adicionadas para lidar com eventos quando o usuário solicita que o ouvinte associe a um endereço de IP e porta de TCP, aceite uma conexão e leia os dados enviados do cliente.

Observação  Apesar do exemplo específico ser auto-contido (cliente e servidor estão no mesmo aplicativo), você normalmente teria aplicativos e servidor e cliente separados.

 

  • Abra a pasta js. Abra o novo arquivo startListener.js e adicione o seguinte código ao arquivo:

        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);
            }
        }
    

Criar o soquete e conectar a um ponto de extremidade remoto

O código nesta etapa adiciona uma função para criar o soquete e conectar ao ponto de extremidade remoto, tipicamente um servidor, usando o método StreamSocket.ConnectAsync. Uma função também é adicionada para tratar casos onde há um erro quando o cliente tenta fazer uma conexão.

  • Abra a pasta js. Abra o novo arquivo connectToListener.js e adicione o seguinte código ao arquivo:

        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 e receber dados no cliente

O código nesta etapa adiciona uma função para enviar dados para o servidor usando métodos na classe Windows.Storage.Stream.DataWriter.

  • Abra a pasta js. Abra um novo arquivo sendData.js e adicione o seguinte código ao arquivo:

        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);
            }
        }
    

Fechar os soquetes

O código nesta etapa fechará os soquetes usando o método StreamSocket.Close. Quando os soquetes forem fechados, todas as operações pendentes serão concluídas as rotinas de erro serão chamadas.

  • Abra a pasta js. Abra o novo arquivo socketClose.js e adicione o seguinte código ao arquivo:

        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.");
        }
    

Executar o aplicativo

  • Para executar o aplicativo, pressione F5 no Visual Studio executar o projeto. Selecione os botões para iniciar o ouvinte, para conectar o cliente ao ouvinte, para enviar dados e para fechar soquetes.

Resumo e próximas etapas

Neste tópico, você criou um aplicativo que usa um soquete de fluxo TCP para estabelecer uma conexão de rede e enviar dados usando um objeto StreamSocket. O aplicativo também mostrou como ouvir uma conexão TCP e aceitar uma conexão do soquete de fluxo que pode ser usada para enviar ou receber dados.

O código-fonte e os arquivos de compilação para este tópico estão disponíveis como o exemplo de StreamSocket.

Você também pode usar um soquete de datagrama para fazer a conexão de rede enviar dados. Para ver um exemplo, consulte Como se conectar com um soquete de datagrama.

Tópicos relacionados

Outros recursos

Conectando-se com soquetes

Como configurar recursos de rede

Como se conectar com um soquete de datagrama

Como habilitar o loopback e depurar o isolamento da rede

Como proteger conexões de soquete com TLS/SSL

Como definir tempos limites em operações de soquetes

Como usar controles de soquete avançados

Solucione problemas e depure conexões de rede

Referência

StreamSocket

StreamSocketListener

Windows.Networking

Windows.Networking.Sockets

Windows.Storage.Stream.DataWriter

Exemplos

Exemplo de StreamSocket