Come connettersi con un socket di flusso (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 abilitare un'app di Windows Runtime all'invio e alla ricezione di dati di rete con un socket TCP mediante StreamSocket. Un socket TCP consente trasferimenti di dati di rete di basso livello nelle due direzioni per le connessioni di lunga durata. I socket TCP costituiscono la funzionalità sottostante utilizzata da gran parte di protocolli di rete in uso su Internet.
Il componente client dell'esempio crea un socket TCP per creare una connessione di rete, usa il socket per inviare dati e quindi lo chiude. Il componente server dell'esempio crea un socket TCP per ascoltare e accettare le connessioni di rete, accetta le connessioni dal socket in entrata, usa il socket per ricevere dati dal client e quindi lo chiude. Questo esempio è fornito nei linguaggi di programmazione JavaScript, C#, VB e C++.
Il componente client dell'esempio dimostra le seguenti funzionalità:
- Usa la classe StreamSocket per creare un socket TCP.
- Crea una connessione di rete a un server TCP di rete con uno dei metodi StreamSocket.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à:
- Usa la classe StreamSocketListener per creare un socket TCP per l'ascolto di una connessione TCP in entrata.
- Associa il socket a un nome di servizio locale per l'ascolto di una connessione di rete in entrata usando il metodo StreamSocketListener.BindServiceNameAsync.
- Ricevi un evento StreamSocketListener.ConnectionReceived che indica che una connessione è stata ricevuta nell'oggetto StreamSocketListener.
- Ricevi i dati dal client usando l'oggetto Streams.DataReader che consente al programmatore di leggere tipi comuni (ad esempio interi e stringhe) su qualsiasi flusso.
- Chiudi il socket.
Nota Per usare questo esempio, è necessario l'accesso alla rete tramite un'interfaccia di loopback.
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
Creare un nuovo progetto
- Apri Microsoft Visual Studio 2013 e scegli Nuovo progetto dal menu File.
- Nell'elenco dei modelli scegli JavaScript.
- In questa sezione scegli Store apps.
- In questa sezione seleziona Universal Apps, Windows apps o Windows Phone apps (in base alla piattaforma di destinazione), e quindi seleziona Applicazione vuota.
- Assegna all'applicazione il nome
socketsSample
e fai clic su OK.
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 StreamSocket 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 StreamSocketListenerper l'ascolto delle connessioni in entrata dagli endpoint remoti in Internet, è necessaria la funzionalità Internet (client e server). Se l'app deve usare il StreamSocketListenerper 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.
Usa Microsoft Visual Studio per aprire il file package.appxmanifest.
Seleziona la scheda Funzionalità.
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).
Salva e chiudi il file manifesto.
Aggiungere l'interfaccia utente HTML
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> 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>
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 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>
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. 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>
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>
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.
Apri la cartella js. Apri il file default.js e aggiungi il codice seguente al file.
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();
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, il socket di lettura del server e diverse variabili per errori ed eventi. Le variabili consentono di verificare se il socket del client è in stato di connessione o di chiusura. In questo passaggio vengono anche definiti il nome host e il nome del servizio (porta TCP) a cui connettersi nel server. I valori di nome host e nome del servizio 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; // 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; } }; })();
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 TCP, 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() { 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); } }
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 StreamSocket.ConnectAsync. 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() { 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); } }
Inviare e ricevere i dati nel client
Il codice mostrato in questo passaggio consente di aggiungere una funzione per inviare i dati al server usando i metodi della classe Windows.Storage.Stream.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; } 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); } }
Chiudere i socket
Il codice mostrato in questo passaggio consente di chiudere i socket usando il metodo StreamSocket.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/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."); }
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 flusso TCP per stabilire una connessione di rete e inviare i dati mediante un oggetto StreamSocket. L'app mostra anche come impostare l'ascolto per una connessione TCP e accettare una connessione da un socket di flusso che è possibile usare per l'invio o la ricezione di dati.
Il codice sorgente e i file di generazione per questo argomento sono disponibili come esempio StreamSocket.
Per creare una connessione di rete per l'invio di dati, puoi anche usare un socket di datagramma. Per un esempio, vedi Come connettersi con un socket di datagramma.
Argomenti correlati
Altre risorse
Come configurare le funzionalità di rete
Come connettersi con un socket di datagramma
Come abilitare il loopback ed eseguire il debug dell'isolamento di rete
Come proteggere le connessioni socket con TLS/SSL
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
Windows.Storage.Stream.DataWriter
Esempi