Como se conectar com um soquete de datagrama (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]

Estes tópicos mostram como usar UDP para enviar e receber dados de rede em um aplicativo do Tempo de Execução do Windows com um DatagramSocket.

O componente cliente do exemplo cria um soquete UDP, usa o soquete para enviar e receber dados e fecha o soquete. O componente de servidor do exemplo cria um soquete UDP para escutar pacotes de rede de entrada, recebe os pacotes UDP de entrada do cliente, envia dados ao cliente e fecha o soquete. Este exemplo é fornecido nas linguagens de programação JavaScript, C# e C++.

O componente cliente do exemplo demonstra os seguintes recursos:

  • Usar a classe DatagramSocket para criar um soquete UDP para o cliente enviar e receber dados.
  • Adicionar um manipulador para um evento DatagramSocket.MessageReceived que indica que um datagrama UDP foi recebido no objeto DatagramSocket.
  • Definir o ponto de extremidade remoto para um servidor de rede UDP para o qual os pacotes devem ser enviados usando um dos métodos DatagramSocket.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.

 

Objetivo: Crie uma conexão de rede para outro computador ou dispositivo usando um soquete DatagramSocket.

Pré-requisitos

Os exemplos a seguir usam JavaScript. Para obter ajuda para criar seu primeiro aplicativo, veja Criar seu primeiro aplicativo da Windows Store em 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

1. 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.

2. 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 DatagramSocket 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 DatagramSocket 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 DatagramSocket 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.

3. 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>
                DatagramSocket is used to create the 'server' side of a connection. It listens on a 'service name' (often a port number) and 
                each time a datagram is received on the port number it fires MessageReceived event.
            </p>
            <p>
                <label for="serviceNameAccept">Service Name:</label>
                <input id="serviceNameAccept" type="text" />
            </p>
            <p>
                <button id="buttonStartListener">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 internationalized
                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" disabled="disabled" />
            </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.
            </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>
    

4. 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.

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

        var sampleTitle = "DatagramSocket";
    
        var scenarios = [
            { url: "/html/startListener.html", title: "Start DatagramSocket Listener" },
            { 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();
    

5. 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 e 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. Essa etapa também define o nome do host e o nome do serviço (porta UDP) para conexão e envio de dados, além do nome do serviço local (porta UDP) no qual aceitar e receber dados. Os valores do nome do host, do nome do serviço remoto e do nome do serviço local são definidos como um valor padrão que pode ser mudado 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;
        socketsSample.listenerOutputStream = null;
        socketsSample.listenerPeerAddress = null;
        socketsSample.listenerPeerPort = null;
        socketsSample.clientSocket = null;
        socketsSample.clientDataWriter = null;
        socketsSample.connected = false;
        socketsSample.closing = false;
        socketsSample.bindingToService = false;
    
        socketsSample.serviceNameAccept = "22112";
        socketsSample.hostNameConnect = "localhost";
        socketsSample.serviceNameConnect = "22112";
    
        socketsSample.close = function () {
    
            socketsSample.closing = true;
    
            if (socketsSample.listener) {
                socketsSample.listener.close();
            }
    
            if (socketsSample.clientSocket) {
                socketsSample.clientSocket.close();
            }
    
            socketsSample.listener = null;
            socketsSample.listenerOutputStream = null;
            socketsSample.listenerPeerAddress = null;
            socketsSample.listenerPeerPort = null;
            socketsSample.clientSocket = null;
            socketsSample.clientDataWriter = null;
            socketsSample.connected = false;
        };
    
        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;
            }
        };
    })();
    

6. 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 se associe a um endereço de IP e uma porta UDP, 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() {
            var serviceName = document.getElementById("serviceNameAccept").value;
            if (serviceName === "") {
                socketsSample.displayStatus("Please provide a service name.");
                return;
            }
    
            if (socketsSample.listener) {
                socketsSample.displayStatus("Already have a listener; call close to close the listener.");
                return;
            }
    
            socketsSample.closing = false;
            socketsSample.bindingToService = true;
            socketsSample.listener = new Windows.Networking.Sockets.DatagramSocket();
            socketsSample.listener.addEventListener("messagereceived", onServerMessageReceived);
            socketsSample.displayStatus("Server: listener creation started.");
            socketsSample.listener.bindServiceNameAsync(serviceName).done(function () {
                socketsSample.displayStatus("Server: listener creation completed.");
                socketsSample.bindingToService = false;
            }, onError);
        }
    
        function onServerMessageReceived(eventArgument) {
            if (socketsSample.listenerOutputStream) {
                echoMessage(socketsSample.listenerOutputStream, eventArgument);
                return;
            }
    
            socketsSample.listener.getOutputStreamAsync(eventArgument.remoteAddress, eventArgument.remotePort).done(function (outputStream) {
                if (!socketsSample.listenerOutputStream) {
                    socketsSample.listenerOutputStream = outputStream;
                    socketsSample.listenerPeerAddress = eventArgument.remoteAddress;
                    socketsSample.listenerPeerPort = eventArgument.remotePort;
                }
    
                echoMessage(socketsSample.listenerOutputStream, eventArgument);
            });
        }
    
        function echoMessage(outputStream, eventArgument) {
            if (socketsSample.listenerPeerAddress !== eventArgument.remoteAddress ||
                socketsSample.listenerPeerPort !== eventArgument.remotePort) {
                socketsSample.displayStatus("Got datagram from " + eventArguments.remoteAddress + ":" + eventArguments.remotePort +
                    ", but already 'connected' to " + socketsSample.listenerPeerAddress + ":" + socketsSample.listenerPeerPort);
                return;
            }
    
            outputStream.writeAsync(eventArgument.getDataReader().detachBuffer()).done(function () {
                // Do nothing - client will print out a message when data is received.
            });
        }
    
        function onError(reason) {
            // Clean up a listener if we failed to bind to a port.
            if (socketsSample.bindingToService) {
                socketsSample.listener = null;
                socketsSample.bindingToService = false;
            }
    
            // 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);
            }
        }
    

7. 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 DatagramSocket.ConnectAsync. Uma função é adicionada para lidar com os casos em que uma mensagem é recebida pelo cliente. 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() {
            var serviceName = document.getElementById("serviceNameConnect").value;
            if (serviceName === "") {
                socketsSample.displayStatus("Please provide a service name.");
                return;
            }
    
            // By default 'hostNameConnect' is disabled and host name validation is not required. When enabling the text
            // box validating the host name is required since it was received from an untrusted source (user input).
            // Note that when enabling the text box users may provide names for hosts on the intErnet that require the
            // "Internet (Client)" capability.
            var hostName;
            try {
                hostName = new Windows.Networking.HostName(document.getElementById("hostNameConnect").value);
            } catch (error) {
                socketsSample.displayStatus("Error: Invalid host name.");
                return;
            }
    
            if (socketsSample.clientSocket) {
                socketsSample.displayStatus("Already have a client; call close to close the listener and the client.");
                return;
            }
    
            socketsSample.closing = false;
            socketsSample.clientSocket = new Windows.Networking.Sockets.DatagramSocket();
            socketsSample.clientSocket.addEventListener("messagereceived", onMessageReceived);
            socketsSample.displayStatus("Client: connection started.");
            socketsSample.clientSocket.connectAsync(hostName, serviceName).done(function () {
                socketsSample.displayStatus("Client: connection completed.");
                socketsSample.connected = true;
            }, onError);
        }
    
        function onMessageReceived(eventArgument) {
            try {
                var messageLength = eventArgument.getDataReader().unconsumedBufferLength;
                var message = eventArgument.getDataReader().readString(messageLength);
                socketsSample.displayStatus("Client: receive message from server \"" + message + "\"");
            } catch (exception) {
                status = Windows.Networking.Sockets.SocketError.getStatus(exception.number);
                if (status === Windows.Networking.Sockets.SocketErrorStatus.connectionResetByPeer) {
                    socketsSample.displayStatus("Peer does not listen on the specific port. Please make sure that you run step 1 first " +
                    "or you have a server properly working on a remote server.");
                } else {
                    socketsSample.displayStatus("Error happened when receiving a datagram: " + exception.message);
                }
            }
        }
    
        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);
            }
        }
    

8. Enviar e receber dados no cliente

O código nesta etapa adiciona uma função para enviar dados ao ponto de extremidade UDP remoto usando métodos na classe Windows.Storage.Streams.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;
            }
    
            if (!socketsSample.clientDataWriter) {
                socketsSample.clientDataWriter = new Windows.Storage.Streams.DataWriter(socketsSample.clientSocket.outputStream);
            }
    
            var string = "Hello World";
            socketsSample.clientDataWriter.writeString(string);
    
            socketsSample.displayStatus("Client sending: " + string + ".");
            socketsSample.clientDataWriter.storeAsync().done(function () {
                socketsSample.displayStatus("Client sent: " + string + ".");
            }, 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);
            }
        }
    

9. Fechar os soquetes

O código nesta etapa fechará os soquetes usando o método DatagramSocket.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/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;
            }
    
            if (!socketsSample.clientDataWriter) {
                socketsSample.clientDataWriter = new Windows.Storage.Streams.DataWriter(socketsSample.clientSocket.outputStream);
            }
    
            var string = "Hello World";
            socketsSample.clientDataWriter.writeString(string);
    
            socketsSample.displayStatus("Client sending: " + string + ".");
            socketsSample.clientDataWriter.storeAsync().done(function () {
                socketsSample.displayStatus("Client sent: " + string + ".");
            }, 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);
            }
        }
    

10. 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 datagrama UDP para estabelecer uma conexão de rede e enviar dados usando um objeto DatagramSocket. O aplicativo também mostrou como ouvir em uma porta UDP e receber dados.

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

Você também pode usar um soquete de fluxo para fazer com que uma conexão de rede usada envie e receba dados. Para ver um exemplo, consulte Como se conectar com um soquete de fluxo.

Tópicos relacionados

Outros recursos

Conectando-se com soquetes

Como configurar recursos de isolamento de rede

Como se conectar com um soquete de fluxo

Como definir tempos limite em operações de soquete

Como usar controles de soquete avançados

Solucionar problemas e depurar conexões de rede

Referência

DatagramSocket

Windows.Networking

Windows.Networking.Sockets

Exemplos

Exemplo de DatagramSocket