Condividi tramite


Come connettersi con un socket di datagramma (HTML)

[ Questo articolo è rivolto agli sviluppatori per Windows 8.x e Windows Phone 8.x che realizzano app di Windows Runtime. Gli sviluppatori che usano Windows 10 possono vedere Documentazione aggiornata ]

Questo argomento mostra come usare UDP per inviare e ricevere dati di rete in un'app di Windows Runtime con un DatagramSocket.

Il componente client dell'esempio crea un socket TCP, usa il socket per inviare e ricevere dati, quindi lo chiude. Il componente server dell'esempio crea un socket UDP per l'ascolto dei pacchetti di rete in entrata, riceve i pacchetti UDP in entrata dal client, invia i dati al client e chiude il socket. Questo esempio è fornito nei linguaggi di programmazione JavaScript, C# e C++.

Il componente client dell'esempio dimostra le seguenti funzionalità:

  • Usa la classe DatagramSocket per creare un socket UDP che consenta al client di inviare e ricevere dati.
  • Aggiungi un gestore per un evento DatagramSocket.MessageReceived che indica che un datagramma UDP è stato ricevuto nell'oggetto DatagramSocket.
  • Imposta l'endpoint remoto per un server di rete UDP in cui i pacchetti devono essere inviati usando uno dei metodi DatagramSocket.ConnectAsync.
  • Invia dati al server usando l'oggetto Streams.DataWriter che consente al programmatore di scrivere tipi comuni (ad esempio interi e stringhe) su qualsiasi flusso.
  • Chiudi il socket.

Il componente server dell'esempio dimostra le seguenti funzionalità:

Nota  Per usare questo esempio, è necessario l'accesso alla rete tramite un'interfaccia di loopback.

 

Obiettivo: Creare una connessione di rete a un altro computer o dispositivo con un socket DatagramSocket.

Prerequisiti

Negli esempi seguenti viene usato JavaScript. Se hai bisogno di aiuto per creare la tua prima app, vedi Creare la prima app di Windows Store in JavaScript.

Per predisporre la tua app di Windows Store per l'uso in rete, devi impostare la funzionalità nel file Package.appxmanifest del progetto. Per una definizione delle singole funzionalità di rete, vedi Come configurare le funzionalità di isolamento della rete.

Istruzioni

1. Creare un nuovo progetto

  1. Apri Microsoft Visual Studio 2013 e scegli Nuovo progetto dal menu File.
  2. Nell'elenco dei modelli scegli JavaScript.
  3. In questa sezione scegli Store apps.
  4. In questa sezione seleziona Universal Apps, Windows apps o Windows Phone apps (in base alla piattaforma di destinazione), e quindi seleziona Applicazione vuota.
  5. Assegna all'applicazione il nome socketsSample e fai clic su OK.

2. Impostare le funzionalità per abilitare l'accesso in rete

Devi impostare le funzionalità di rete per l'app se quest'ultima richiede l'accesso alla rete. Le funzionalità di rete devono essere impostate per un'app che usa un DatagramSocket per connettersi a un servizio di rete.

Se l'app deve essere in grado di connettersi come client a servizi remoti su Internet, è necessaria la funzionalità Internet (client). Se l'app deve essere in grado di connettersi come client a servizi remoti su una rete di casa o di lavoro, è necessaria la funzionalità Reti private (client e server).

Se l'app deve usare il DatagramSocketper l'ascolto delle connessioni in entrata dagli endpoint remoti in Internet, è necessaria la funzionalità Internet (client e server). Se l'app deve usare il DatagramSocketper l'ascolto delle connessioni in entrata da endpoint remoti su una rete di casa o di lavoro, è necessaria la funzionalità Reti private (client e server).

Nota  In Windows Phone, c'è solo una funzionalità di rete Internet (client e server) che consente l'accesso a tutte le reti per l'app.

 

Se il componente server di questo esempio in ascolto delle connessioni in entrata è in esecuzione sullo stesso dispositivo del componente client, è necessario l'accesso loopback. Le app sviluppate ed eseguite in Visual Studio 2013 verranno registrate automaticamente come esenti dalle restrizioni loopback. Per altre informazioni, vedi Come abilitare il loopback ed eseguire il debug dell'isolamento di rete.

Per altre informazioni sull'accesso di rete, vedi Come configurare le funzionalità di isolamento della rete.

Questi passaggi sono necessari per impostare le funzionalità di rete per un'app prima che venga distribuita, in caso di accesso a un servizio di rete su Internet o a una rete domestica o aziendale.

  1. Usa Microsoft Visual Studio per aprire il file package.appxmanifest.

  2. Seleziona la scheda Funzionalità.

  3. Per sviluppare la versione di Windows dell'esempio, seleziona le funzionalità Internet (client) e Reti private (client e server).

    Per sviluppare la versione di Windows Phone dell'esempio, seleziona la funzionalità Internet (client e server).

  4. Salva e chiudi il file manifesto.

3. Aggiungere l'interfaccia utente HTML

  1. Apri la cartella html. Apri un nuovo file startListener.html e aggiungi il codice HTML seguente alle sezioni <head> e <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. Apri la cartella html. Apri un nuovo file connectToListener.html e aggiungi il codice HTML seguente alle sezioni <head> e <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. Apri la cartella html. Apri un nuovo file sendData.html e aggiungi il codice HTML seguente alle sezioni <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. Apri la cartella html. Apri un nuovo file closeSocket.html e aggiungi il codice HTML seguente alle sezioni <head> e <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. Definire l'esempio e gli scenari

Il codice mostrato in questo passaggio definisce l'esempio, i file HTML e gli scenari usati dall'esempio. Il codice aggiunge inoltre listener di eventi e avvia l'app. Le opzioni di scenario consentono all'utente di avviare il listener del socket, avviare il client affinché si connetta al listener e invii alcuni dati al server e di chiudere i socket.

  1. Apri la cartella js. Apri il file default.js e aggiungi il codice seguente al file.

        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. Definire le variabili per i socket e le funzioni di eventi

Il codice mostrato in questo passaggio crea numerose variabili, tra cui il socket del listener, il socket del client e diverse variabili per errori ed eventi. Le variabili consentono di verificare se il socket del client è in stato di connessione o di chiusura. Questo passaggio definisce inoltre il nome host e il nome del servizio (porta UDP) a cui connettesi e inviare i dati, come pure il nome del servizio locale (porta UDP) su cui accettare e ricevere i dati. I valori di nome host remoto, nome del servizio remoto e nome del servizio locale sono impostati su un valore predefinito che può essere modificato nell'interfaccia utente.

  • Apri la cartella js. Apri il file socketsSample.js e aggiungi il codice seguente al file.

    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. Creare un listener e avviare l'ascolto di un nome di servizio (porta)

Il codice mostrato in questa sezione consente di creare un listener e di avviare l'ascolto. Sono disponibili funzioni aggiuntive per la gestione di eventi quando l'utente richiede che il listener esegua l'associazione a un indirizzo IP e a una porta UDP, che accetti una connessione e che legga i dati inviati dal client.

Nota  Sebbene questo esempio specifico sia completo (client e server sono nella stessa app), in genere sarebbero necessarie due app client e server separate.

 

  • Apri la cartella js. Apri il file startListener.js e aggiungi il codice seguente al file:

        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. Creare il socket ed eseguire la connessione a un endpoint remoto

Il codice mostrato in questo passaggio aggiunge una funzione che consente di creare il socket e di connettersi all'endpoint remoto, in genere un server, usando il metodo DatagramSocket.ConnectAsync. Quando il client riceve un messaggio viene aggiunta una funzione da gestire. Viene anche aggiunta una funzione per gestire i casi in cui si verifica un errore quando il client tenta di eseguire una connessione.

  • Apri la cartella js. Apri il file connectToListener.js e aggiungi il codice seguente al file:

        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. Inviare e ricevere i dati nel client

Il codice mostrato in questo passaggio consente di aggiungere una funzione per inviare i dati all'endpoint UDP remoto usando i metodi della classe Windows.Storage.Streams.DataWriter.

  • Apri la cartella js. Apri un nuovo file sendData.js e aggiungi il codice seguente al file:

        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. Chiudere i socket

Il codice mostrato in questo passaggio consente di chiudere i socket usando il metodo DatagramSocket.Close. Quando i socket vengono chiusi, tutte le operazioni in sospeso terminano e vengono chiamate le routine di errore.

  • Apri la cartella js. Apri il file socketClose.js e aggiungi il codice seguente al file:

        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. Eseguire l'applicazione

  • Per eseguire l'app, premi F5 in Visual Studio per eseguire il progetto. Seleziona i pulsanti per avviare il listener, connettere il client al listener, inviare i dati e chiudere i socket.

Riepilogo e passaggi successivi

In questo argomento hai creato un'app che usa un socket di datagramma UDP per stabilire una connessione di rete e inviare i dati mediante un oggetto DatagramSocket. L'app mostra inoltre come impostare l'ascolto su una porta UDP e ricevere i dati.

Il codice sorgente e i file di generazione per questo argomento sono disponibili come esempio DatagramSocket.

Per creare una connessione di rete per l'invio e la ricezione di dati, puoi anche usare un socket di flusso. Per un esempio, vedi Come connettersi con un socket di flusso.

Argomenti correlati

Altre risorse

Connessione con i socket

Come configurare le funzionalità di isolamento della rete

Come connettersi con un socket di flusso

Come impostare i timeout nelle operazioni socket

Come usare i controlli avanzati dei socket

Risolvere i problemi ed eseguire il debug delle connessioni di rete

Riferimento

DatagramSocket

Windows.Networking

Windows.Networking.Sockets

Esempi

Esempio DatagramSocket