Comment établir une connexion à l’aide d’un socket datagramme (HTML)
[ Cet article est destiné aux développeurs de Windows 8.x et Windows Phone 8.x qui créent des applications Windows Runtime. Si vous développez une application pour Windows 10, voir la Documentation ]
Cette rubrique montre comment utiliser le protocole UDP pour envoyer et recevoir des données réseau dans une application Windows Runtime avec un DatagramSocket.
Le composant client de l’exemple crée un socket UDP, utilise ce socket pour envoyer et recevoir des données, puis le ferme. Le composant serveur de l’exemple crée un socket UDP pour écouter les paquets réseau entrants, reçoit les paquets UDP entrants à partir du client, envoie les données au client, puis ferme le socket. Cet exemple est fourni dans les langages de programmation JavaScript, C# et C++.
Le composant client de l’exemple présente les fonctionnalités suivantes :
- utiliser la classe DatagramSocket pour créer un socket UDP afin que le client envoie et reçoive des données ;
- ajouter un gestionnaire pour un événement DatagramSocket.MessageReceived qui indique si un datagramme UDP a été reçu sur l’objet DatagramSocket ;
- définir le point de terminaison distant d’un serveur réseau UDP où les paquets doivent être envoyés à l’aide de l’une des méthodes DatagramSocket.ConnectAsync ;
- envoyer des données au serveur à l’aide de l’objet Streams.DataWriter qui permet à un programmeur d’écrire des types courants (des entiers et des chaînes, par exemple) sur un flux ;
- fermer le socket.
Le composant serveur de l’exemple présente les fonctionnalités suivantes :
- utiliser la classe DatagramSocket pour créer un socket UDP destiné à écouter et recevoir des paquets de datagramme entrants, ainsi que pour envoyer des paquets ;
- ajouter un gestionnaire pour un événement DatagramSocket.MessageReceived qui indique si un datagramme UDP a été reçu sur l’objet DatagramSocket ;
- lier le socket à un nom de service local pour écouter les paquets UDP entrants à l’aide de la méthode DatagramSocket.BindServiceNameAsync ;
- recevoir un événement DatagramSocket.MessageReceived qui indique si un datagramme UDP a été reçu sur l’objet DatagramSocket ;
- recevoir des données du client à l’aide du gestionnaire DatagramSocket.MessageReceived. L’objet DatagramSocketMessageReceivedEventArgs passé au gestionnaire DatagramSocket.MessageReceived permet à une application de recevoir des données à partir du client, ainsi que de déterminer l’adresse distante et le port qui ont envoyé les données ;
- fermer le socket.
Remarque Pour utiliser cet exemple, vous devez disposer d’un accès réseau à l’aide de l’interface de bouclage.
Objectif: créer une connexion réseau à un autre ordinateur ou périphérique en utilisant un socket DatagramSocket.
Prérequis
Les exemples suivants utilisent JavaScript. Pour obtenir de l’aide sur la création de votre première application, voir Créer votre première application du Windows Store en JavaScript.
Pour préparer votre application du Windows Store à une mise en réseau, vous devez définir cette fonctionnalité dans le fichier Package.appxmanifest du projet. Pour obtenir une définition de chaque fonctionnalité réseau, voir Comment configurer les fonctionnalités d’isolement réseau.
Instructions
1. Créer un projet
- Ouvrez Microsoft Visual Studio 2013 et sélectionnez Nouveau projet dans le menu Fichier.
- Dans la liste des modèles, choisissez JavaScript.
- Sous la section, choisissez Store apps.
- Sous la section, sélectionnez Universal Apps, Windows apps, ou Windows Phone apps (en fonction de votre plateforme cible), puis Application vide.
- Nommez l’application
socketsSample
et cliquez sur OK.
2. Définir les fonctionnalités pour activer l’accès réseau
Vous devez définir les fonctionnalités réseau pour votre application si celle-ci a besoin d’un accès réseau. Les fonctionnalités réseau doivent être définies pour une application qui utilise un DatagramSocket pour se connecter à un service réseau.
Si l’application doit être en mesure de se connecter en qualité de client à des services distants sur Internet, la fonctionnalité Internet (client) est alors nécessaire. Si l’application doit être en mesure de se connecter en qualité de client à des services distants sur un réseau domestique ou d’entreprise, la fonctionnalité Réseaux privés (client et serveur) est requise.
Si l’application doit utiliser le DatagramSocket pour écouter les connexions entrantes à partir de points de terminaison distants sur Internet, la fonctionnalité Internet (client et serveur) est alors nécessaire. Si l’application doit utiliser le DatagramSocket pour écouter les connexions entrantes à partir de points de terminaison distants sur un réseau domestique ou d’entreprise, la fonctionnalité Réseaux privés (client et serveur) est requise.
Remarque Sur Windows Phone, une seule fonctionnalité réseau, Internet (client et serveur), permet à l’application d’accéder à tous les réseaux.
Si le composant serveur de cet exemple qui écoute les connexions entrantes s’exécute sur le même appareil que le composant client, un accès par bouclage s’avère nécessaire. Les applications développées et exécutées dans Visual Studio 2013 sont automatiquement inscrites comme n’étant pas concernées par les restrictions de bouclage. Pour plus d’informations, voir Comment activer le bouclage et déboguer l’isolement réseau.
Pour plus d’informations sur l’accès réseau, voir Comment configurer les fonctionnalités d’isolement réseau.
Ces étapes sont utiles pour définir les fonctionnalités réseau d’une application avant son déploiement si elle a accès à un service réseau sur Internet ou sur un réseau domestique ou d’entreprise.
Utilisez Microsoft Visual Studio pour ouvrir le fichier package.appxmanifest.
Sélectionnez l’onglet Capacités.
Pour générer la version Windows de l’exemple, sélectionnez les fonctionnalités Internet (Client) et Réseaux privés (client et serveur).
Pour générer la version Windows Phone de l’exemple, sélectionnez la fonctionnalité Internet (client et serveur).
Enregistrez et fermez le fichier manifeste.
3. Ajouter une interface utilisateur HTML
Ouvrez le dossier html. Ouvrez un nouveau fichier startListener.html, puis ajoutez le code HTML suivant dans les sections <head> et <body> du fichier.
<!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>
Ouvrez le dossier html. Ouvrez un nouveau fichier connectToListener.html, puis ajoutez le code HTML suivant dans les sections <head> et <body> du fichier.
<!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>
Ouvrez le dossier html. Ouvrez un nouveau fichier sendData.html et ajoutez le code HTML suivant aux sections <head> et <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>
Ouvrez le dossier html. Ouvrez un nouveau fichier closeSocket.html, puis ajoutez le code HTML suivant dans les sections <head> et <body> du fichier.
<!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. Définir l’exemple et les scénarios
Le code présenté dans cette étape définit l’exemple, les fichiers HTML et les scénarios utilisés par l’exemple. Il ajoute également des détecteurs d’événements et démarre l’application. Les options du scénario permettent à l’utilisateur de démarrer l’écouteur de socket, de démarrer le client pour qu’il se connecte à l’écouteur, de faire en sorte que le client envoie des données au serveur et de fermer les sockets.
Ouvrez le dossier js. Ouvrez le fichier default.js et ajoutez-y le code suivant.
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. Définir des variables pour les sockets et les fonctions d’événement
Le code présenté dans cette étape crée différentes variables, notamment le socket d’écoute, le socket client et différentes variables pour les erreurs et les événements. Des variables sont créées afin de suivre l’état du socket client (connecté ou en cours de fermeture). Cette étape définit également le nom d’hôte et le nom de service (port UDP) auxquels se connecter et envoyer des données, ainsi que le nom de service local (port UDP) sur lequel accepter et recevoir des données. Le nom d’hôte distant, le nom de service distant et le nom de service local sont définis sur une valeur par défaut qui peut être modifiée dans l’interface utilisateur.
Ouvrez le dossier js. Ouvrez un nouveau fichier socketsSample.js et ajoutez-y le code suivant.
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. Créer un écouteur et démarrer l’écoute d’un nom de service (port)
Le code présenté dans cette étape crée un écouteur et démarre l’écoute. Des fonctions sont également ajoutées pour gérer les événements lorsque l’utilisateur demande que l’écouteur crée une liaison à une adresse IP et un port UDP, accepte une connexion et lise les données envoyées depuis le client.
Remarque Dans cet exemple particulier, le client et le serveur se trouvent dans la même application, mais vous aurez généralement des applications cliente et serveur distinctes.
Ouvrez le dossier js. Ouvrez un nouveau fichier startListener.js, puis ajoutez le code suivant dans ce fichier :
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. Créer le socket et établir une connexion à un point de terminaison distant
Le code présenté dans cette étape ajoute une fonction permettant de créer le socket et d’établir une connexion au point de terminaison distant, généralement un serveur, à l’aide de la méthode DatagramSocket.ConnectAsync. Une fonction est ajoutée pour gérer ce qui se passe lorsqu’un message est reçu par le client. Une fonction est également ajoutée pour traiter les cas où une erreur se produit lorsque le client essaie d’établir une connexion.
Ouvrez le dossier js. Ouvrez un nouveau fichier connectToListener.js, puis ajoutez le code suivant dans ce fichier :
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. Envoyer et recevoir des données sur le client
Le code présenté dans cette étape ajoute une fonction permettant d’envoyer des données au point de terminaison UDP distant à l’aide des méthodes de la classe Windows.Storage.Streams.DataWriter.
Ouvrez le dossier js. Ouvrez un nouveau fichier sendData.js et ajoutez-y le code suivant.
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. Fermer les sockets
Le code présenté dans cette étape ferme le socket à l’aide de la méthode DatagramSocket.Close. Lorsque les sockets sont fermés, toutes les opérations en attente sont terminées et les routines d’erreur sont appelées.
Ouvrez le dossier js. Ouvrez un nouveau fichier socketClose.js, puis ajoutez le code suivant dans ce fichier :
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. Exécuter l’application
- Pour exécuter l’application, appuyez sur la touche F5 dans Visual Studio pour exécuter le projet. Sélectionnez les boutons dans l’ordre pour démarrer l’écouteur, connecter le client à l’écouteur, envoyer des données et fermer les sockets.
Récapitulatif et étapes suivantes
Dans cette rubrique, vous avez créé une application qui utilise un socket datagramme UDP pour établir une connexion réseau et envoyer des données à l’aide d’un objet DatagramSocket. L’application a également montré comment écouter sur un port UDP et recevoir des données.
Le code source et les fichiers de génération de cette rubrique sont disponibles dans l’exemple DatagramSocket.
Vous pouvez également utiliser un socket de flux pour établir une connexion réseau afin d’envoyer et de recevoir des données. Pour obtenir un exemple, voir Comment établir une connexion à l’aide d’un socket de flux.
Rubriques associées
Autres ressources
Comment configurer les fonctionnalités d’isolement réseau
Comment établir une connexion à l’aide d’un socket de flux
Comment définir des délais d’attente sur les opérations de socket
Comment utiliser des contrôles de socket avancés
Débogage et résolution des problèmes liés aux connexions réseau
Référence
Exemples