Transport: UDP
Cet exemple montre comment implémenter le mode unicast et multicast UDP en tant que transport Windows Communication Foundation (WCF) personnalisé. Il décrit la procédure recommandée pour créer un transport personnalisé dans WCF, en utilisant l'infrastructure de canal et les meilleures pratiques WCF suivantes. Les étapes de la création d'un transport personnalisé sont les suivantes :
- Déterminez le canal Message Exchange Patterns (IOutputChannel, IInputChannel, IDuplexChannel, IRequestChannel ou IReplyChannel) que ChannelFactory et ChannelListener prendront en charge. Déterminez ensuite si vous prendrez en charge les variantes de session de ces interfaces.
- Créez une fabrication et un écouteur de canal qui prennent en charge votre modèle d'échange de messages.
- Assurez-vous que les exceptions spécifiques au réseau sont normalisées selon la classe dérivée appropriée de CommunicationException.
- Ajoutez un élément <binding> qui ajoute le transport personnalisé à une pile de canaux. Pour plus d'informations, consultez Adding a Binding Element.
- Ajoutez une section d'extension d'élément de liaison afin d'exposer le nouvel élément de liaison au système de configuration.
- Ajoutez des extensions de métadonnées pour communiquer des fonctionnalités à d'autres points de terminaison.
- Ajoutez une liaison qui préconfigure une pile d'éléments de liaison d'après un profil bien défini. Pour plus d'informations, consultez Adding a Standard Binding.
- Ajoutez une section de liaison ainsi qu'un élément de configuration de liaison afin d'exposer la liaison au système de configuration. Pour plus d'informations, consultez Adding Configuration Support.
Modèles d'échange de messages
La première étape de l'écriture d'un transport personnalisé consiste à déterminer les MEP (Message Exchange Pattern, modèle d'échange de messages) requis pour le transport. Trois MEP sont disponibles :
- Datagramme (IInputChannel/IOutputChannel)
Lorsque vous utilisez un MEP datagramme, un client envoie un message en utilisant un échange de type « déclenché et oublié » (fire and forget). Un échange de ce type requiert une confirmation hors bande de la réussite de la remise. Le message peut être perdu lors de la transmission et ne jamais atteindre le service. Si l'opération d'envoi s'exécute correctement au niveau du client, cela ne garantit pas que le point de terminaison distant a effectivement reçu le message. Le datagramme est un bloc de construction de messagerie fondamental. Vous pouvez en effet définir vos propres protocoles au-dessus de ce bloc, notamment des protocoles fiables et sécurisés. Les canaux de datagramme du client implémentent l'interface IOutputChannel et ceux du service implémentent l'interface IInputChannel. - Demande-réponse (IRequestChannel/IReplyChannel)
Dans ce MEP, un message est envoyé et une réponse est reçue. Ce modèle se compose de paires demande-réponse. Parmi les exemples d'appels demande-réponse figurent notamment les appels de procédure distante (RPC) et les demandes GET de navigateur. Ce modèle est également connu sous le nom de mode semi-duplex. Dans ce MEP, les canaux du client implémentent IRequestChannel et ceux du service implémentent IReplyChannel. - Duplex (IDuplexChannel)
Le MEP duplex permet à un nombre aléatoire de messages d'être envoyés par un client et d'être reçus dans un ordre indifférencié. Le MEP duplex est similaire à une conversation téléphonique, où chaque mot prononcé correspond à un message. Les deux côtés pouvant envoyer et recevoir des messages dans ce MEP, l'interface implémentée par les canaux du client et du service est IDuplexChannel.
Chacun de ces MEP peut également prendre en charge des sessions. Les fonctionnalités fournies par un canal de session permettent de corréler tous les messages envoyés et reçus sur un canal. Le modèle demande-réponse correspond à une session autonome à deux messages, la demande et la réponse étant corrélées. En revanche, le modèle demande-réponse qui prend en charge les sessions implique que toutes les paires demande/réponse sur ce canal soient corrélées les unes avec les autres. Six MEP sont donc disponibles au total : datagramme, demande-réponse, duplex, datagramme avec sessions, demande-réponse avec sessions et duplex avec sessions.
Remarque : |
---|
Concernant le transport UDP, le seul MEP pris en charge est datagramme, le protocole UDP étant de part nature un protocole de type « déclenché et oublié ». |
ICommunicationObject et cycle de vie des objets WCF
WCF a une machine d'état commune permettant de gérer le cycle de vie des objets tels que IChannel, IChannelFactory et IChannelListener utilisés pour la communication. Ces objets de communication peuvent avoir cinq états différents. Ces états sont représentés par l'énumération CommunicationState et sont les suivants :
- Created : état d'un ICommunicationObject
- Opening : les objects passent à cet état lorsque Open
- Opened : les objets passent à cet état lorsque le processus d'ouverture est terminé. Cette transition est uniquement valide à partir de l'état Opening. À ce stade, l'objet est totalement utilisable pour le transfert.
- Closing : les objets passent à cet état lorsque Close
- Closed : dans cet état, les objets ne sont plus utilisables. En général, la configuration est encore accessible pour l'inspection, mais aucune communication ne peut se produire. Cet état est équivalent à la suppression des objets.
- Faulted : dans cet état, les objets sont accessibles pour l'inspection, mais e sont plus utilisables. Lorsqu'une erreur non récupérable se produit, l'objet passe à cet état. La seule transition valide à partir de cet état est l'état
Closed
.
Des événements se déclenchent pour chaque transition d'état. La méthode Abort
peut être appelée à tout moment et provoquer la transition immédiate de l'objet de son état actuel à l'état Closed. L'appel de Abort termine toute tâche inachevée.
Fabrication et écouteur de canal
L'étape suivante de l'écriture d'un transport personnalisé consiste à créer une implémentation de IChannelFactory pour les canaux clients et de IChannelListener pour les canaux de service. La couche de canal utilise un modèle de fabrication pour construire des canaux. WCF fournit des assistants de la classe de base dans le cadre de ce processus.
- La classe CommunicationObject implémente ICommunicationObject et applique la machine d'état précédemment décrite à l'étape 2.
- La classe
- La classe
CreateChannel
dans une méthode abstraiteOnCreateChannel
. - La classe
Dans cet exemple, l'implémentation de la fabrication est contenue dans UdpChannelFactory.cs et l'implémentation de l'écouteur est contenue dans UdpChannelListener.cs. Les implémentations IChannel sont contenues dans UdpOutputChannel.cs et UdpInputChannel.cs.
Fabrication de canal UDP
``UdpChannelFactory
dérive de ChannelFactoryBase. L'exemple substitue GetProperty pour fournir un accès à la version de message du codeur de message. L'exemple substitue également OnClose afin de nous permettre de détruire notre instance de BufferManager lors des transitions de la machine d'état.
Canal de sortie UDP
``UdpOutputChannel
implémente IOutputChannel. Le constructeur valide les arguments et construit un objet EndPoint de destination reposant sur le EndpointAddress qui est passé.
this.socket = new Socket(this.remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
Le canal peut être fermé de façon appropriée ou incorrecte. Si le canal est fermé de façon appropriée, le socket est fermé et un appel à la méthode OnClose
de la classe de base est effectué. Si une exception est levée, l'infrastructure appelle Abort
pour s'assurer que le canal est nettoyé.
this.socket.Close(0);
Nous implémentons ensuite Send()
et BeginSend()
/EndSend()
. Deux phases peuvent alors être distinguées. Tout d'abord, la sérialisation du message dans un tableau d'octets.
ArraySegment<byte> messageBuffer = EncodeMessage(message);
Puis, l'envoi des données résultantes sur le câble.
this.socket.SendTo(messageBuffer.Array, messageBuffer.Offset, messageBuffer.Count, SocketFlags.None, this.remoteEndPoint);
UdpChannelListener
L'
UdpChannelListener implémenté par l'exemple dérive de la classe ChannelListenerBase. Il utilise un socket UDP unique pour recevoir des datagrammes. La méthode OnOpen
reçoit des données à l'aide du socket UDP dans une boucle asynchrone. Les données sont ensuite converties en messages à l'aide de l'infrastructure de codage de message.
message = MessageEncoderFactory.Encoder.ReadMessage(new ArraySegment<byte>(buffer, 0, count), bufferManager);
Étant donné que le même canal de datagramme représente des messages qui arrivent de plusieurs sources, UdpChannelListener
est un écouteur singleton. Il y a, au plus, un IChannel
actif associé à cet écouteur. L'exemple en génère un autre uniquement si un canal retourné par la méthode AcceptChannel
est supprimé par la suite. Lorsqu'un message est reçu, il est mis en file d'attente dans ce canal singleton.
UdpInputChannel
La classe ``UdpInputChannel
implémente IInputChannel
. Elle se compose d'une file d'attente de messages entrants remplie par le socket de UdpChannelListener
. Ces messages sont extraits de la file d'attente par la méthode IInputChannel.Receive``
.
Ajout d'un élément de liaison
Maintenant que les fabrications de canaux sont construites, nous devons les exposer à l'exécution de ServiceModel via une liaison. Une liaison est une collection d'éléments de liaison qui représente la pile de communication associée à une adresse de service. Chaque élément de la pile est représenté par un élément <binding>.
Dans notre exemple, l'élément de liaison est UdpTransportBindingElement
, lequel dérive de TransportBindingElement. Il substitue les méthodes suivantes pour générer les fabrications associées à notre liaison.
public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
return (IChannelFactory<TChannel>)(object)new UdpChannelFactory(this, context);
}
public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
return (IChannelListener<TChannel>)(object)new UdpChannelListener(this, context);
}
Il contient également des membres permettant de cloner BindingElement
et de retourner notre schéma (soap.udp).
Ajout de la prise en charge des métadonnées pour un élément de liaison de transport
Pour intégrer notre transport dans le système de métadonnées, nous devons prendre à la fois en charge l'importation et l'exportation de stratégie. Cela nous permet de générer des clients de notre liaison via ServiceModel Metadata Utility Tool (Svcutil.exe).
Ajout de la prise en charge WSDL
L'élément de liaison de transport d'une liaison est chargé d'exporter et d'importer les informations d'adressage dans les métadonnées. Lors de l'utilisation d'une liaison SOAP, l'élément de liaison de transport doit également exporter un URI de transport correct dans les métadonnées.
Exportation WSDL
Pour exporter des informations d'adressage, UdpTransportBindingElement
implémente l'interface IWsdlExportExtension
. La méthode ExportEndpoint
ajoute les informations d'adressage correctes au port WSDL.
if (context.WsdlPort != null)
{
AddAddressToWsdlPort(context.WsdlPort, context.Endpoint.Address, encodingBindingElement.MessageVersion.Addressing);
}
L'implémentation UdpTransportBindingElement
de la méthode ExportEndpoint
exporte également un URI de transport lorsque le point de terminaison utilise une liaison SOAP.
WsdlNS.SoapBinding soapBinding = GetSoapBinding(context, exporter);
if (soapBinding != null)
{
soapBinding.Transport = UdpPolicyStrings.UdpNamespace;
}
Importation WSDL
Pour étendre le système d'importation WSDL afin de gérer l'importation des adresses, nous devons ajouter la configuration suivante au fichier de configuration de Svcutil.exe, tel qu'indiqué dans le fichier Svcutil.exe.config.
<configuration>
<system.serviceModel>
<client>
<metadata>
<wsdlImporters>
<extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
</policyImporters>
</metadata>
</client>
</system.serviceModel>
</configuration>
Lorsque vous exécutez Svcutil.exe, deux méthodes permettent de faire en sorte que Svcutil.exe charge les extensions d'importation WSDL :
- Pointez Svcutil.exe sur le fichier de configuration en utilisant /SvcutilConfig:<fichier>.
- Ajoutez la section de configuration à Svcutil.exe.config dans le répertoire où se trouve Svcutil.exe.
Le type UdpBindingElementImporter
implémente l'interface IWsdlImportExtension
. La méthode ImportEndpoint
importe l'adresse à partir du port WSDL.
BindingElementCollection bindingElements = context.Endpoint.Binding.CreateBindingElements();
TransportBindingElement transportBindingElement = bindingElements.Find<TransportBindingElement>();
if (transportBindingElement is UdpTransportBindingElement)
{
ImportAddress(context);
}
Ajout de la prise en charge de la stratégie
L'élément de liaison personnalisé peut exporter des assertions de stratégie dans la liaison WSDL d'un point de terminaison de service pour exprimer les fonctionnalités de cet élément de liaison.
Exportation de stratégie
Le type UdpTransportBindingElement
implémente ``IPolicyExportExtension
pour ajouter la prise en charge de l'exportation de stratégie. En conséquence, System.ServiceModel.MetadataExporter
inclut UdpTransportBindingElement
dans la génération de stratégie des liaisons qui l'incluent.
Dans IPolicyExportExtension.ExportPolicy
, nous ajoutons une assertion pour UDP et une autre si nous sommes en mode multicast. Cela est dû au fait que le mode multicast affecte la manière dont la pile est construite, et doit donc être coordonné entre les deux côtés.
ICollection<XmlElement> bindingAssertions = context.GetBindingAssertions();
XmlDocument xmlDocument = new XmlDocument();
bindingAssertions.Add(xmlDocument.CreateElement(
UdpPolicyStrings.Prefix, UdpPolicyStrings.TransportAssertion, UdpPolicyStrings.UdpNamespace));
if (Multicast)
{
bindingAssertions.Add(xmlDocument.CreateElement(
UdpPolicyStrings.Prefix, UdpPolicyStrings.MulticastAssertion, UdpPolicyStrings.UdpNamespace));
}
Les éléments de liaison de transport personnalisés étant chargés de gérer l'adressage, l'implémentation IPolicyExportExtension
sur UdpTransportBindingElement
doit également gérer l'exportation des assertions de stratégie WS-Addressing appropriées pour indiquer la version de WS-Addressing utilisée.
AddWSAddressingAssertion(context, encodingBindingElement.MessageVersion.Addressing);
Importation de stratégie
Pour étendre le système d'importation de stratégie, nous devons ajouter la configuration suivante au fichier de configuration de Svcutil.exe, tel qu'indiqué dans le fichier Svcutil.exe.config.
<configuration>
<system.serviceModel>
<client>
<metadata>
<policyImporters>
<extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
</policyImporters>
</metadata>
</client>
</system.serviceModel>
</configuration>
Puis nous implémentons IPolicyImporterExtension
à partir de la classe enregistrée (UdpBindingElementImporter
). Dans ImportPolicy()
, nous examinons les assertions dans notre espace de noms, puis traitons celles permettant de générer le transport et vérifions s'il est multicast. Nous devons également supprimer les assertions que nous gérons de la liste des assertions de liaison. Une fois encore, il existe deux méthodes d'intégration possibles lorsque vous exécutez Svcutil.exe :
- Pointez Svcutil.exe sur le fichier de configuration en utilisant /SvcutilConfig:<fichier>.
- Ajoutez la section de configuration à Svcutil.exe.config dans le répertoire où se trouve Svcutil.exe.
Ajout d'une liaison standard
Notre élément de liaison peut être utilisé des deux façons suivantes :
- Via une liaison personnalisée : une liaison personnalisée permet à l'utilisateur de créer sa propre la liaison en fonction d'un ensemble arbitraire d'éléments de liaison.
- En utilisant une liaison fournie par le système qui inclut notre élément de liaison. WCF fournit un certains nombre de ces liaisons définies par le système, telles que
BasicHttpBinding
,NetTcpBinding
etWsHttpBinding
. Chacune de ces liaisons est associée à un profil bien défini.
L'exemple implémente la liaison de profil dans SampleProfileUdpBinding
, lequel dérive de Binding. SampleProfileUdpBinding
contient jusqu'à quatre éléments de liaison : UdpTransportBindingElement
, TextMessageEncodingBindingElement CompositeDuplexBindingElement
et ReliableSessionBindingElement
.
public override BindingElementCollection CreateBindingElements()
{
BindingElementCollection bindingElements = new BindingElementCollection();
if (ReliableSessionEnabled)
{
bindingElements.Add(session);
bindingElements.Add(compositeDuplex);
}
bindingElements.Add(encoding);
bindingElements.Add(transport);
return bindingElements.Clone();
}
Ajout d'un importateur de liaison standard personnalisé
Par défaut, Svcutil.exe et le type WsdlImporter reconnaissent et importent les liaisons définies par le système. Sinon, la liaison est importée en tant qu'instance CustomBinding. Pour permettre à Svcutil.exe et WsdlImporter d'importer SampleProfileUdpBinding
, UdpBindingElementImporter
agit également comme un importateur de liaison standard personnalisé.
Un importateur de liaison standard personnalisé implémente la méthode ImportEndpoint
sur l'interface IWsdlImportExtension
pour examiner l'instance CustomBinding
importée à partir des métadonnées afin de vérifier si elle peut avoir été générée par une liaison standard spécifique.
if (context.Endpoint.Binding is CustomBinding)
{
Binding binding;
if (transportBindingElement is UdpTransportBindingElement)
{
//if TryCreate is true, the CustomBinding will be replace by a SampleProfileUdpBinding in the
//generated config file for better typed generation.
if (SampleProfileUdpBinding.TryCreate(bindingElements, out binding))
{
binding.Name = context.Endpoint.Binding.Name;
binding.Namespace = context.Endpoint.Binding.Namespace;
context.Endpoint.Binding = binding;
}
}
}
En général, l'implémentation d'un importateur de liaison standard personnalisé implique la vérification des propriétés des éléments de liaison importés afin de s'assurer que seules les propriétés pouvant avoir été définies par la liaison standard ont été modifiées et que toutes les autres ont été définies à leurs valeurs par défaut. L'une des stratégies de base permettant d'implémenter un importateur de liaison standard consiste à créer une instance de la liaison standard, à propager les propriétés des éléments de liaison vers l'instance de liaison standard que la liaison standard prend en charge, et à comparer les éléments de liaison de la liaison standard avec les éléments de liaison importés.
Ajout de la prise en charge de la configuration
Pour exposer notre transport via la configuration, nous devons implémenter deux sections de configuration. La première est BindingElementExtensionElement
pour UdpTransportBindingElement
. C'est de cette façon que les implémentations CustomBinding
référencent notre élément de liaison. La deuxième est Configuration
pour SampleProfileUdpBinding
.
Élément d'extension de l'élément de liaison
La
section ``UdpTransportElement
est un BindingElementExtensionElement
qui expose UdpTransportBindingElement
au système de configuration. Avec quelques substitutions de base, nous définissons le nom de notre section de configuration, le type de notre élément de liaison et la méthode utilisée pour le créer. Nous pouvons ensuite enregistrer notre section d'extension dans un fichier de configuration, tel qu'indiqué dans le code suivant.
<configuration>
<system.serviceModel>
<extensions>
<bindingElementExtensions>
<add name="udpTransport" type="Microsoft.ServiceModel.Samples.UdpTransportElement, UdpTransport />
</bindingElementExtensions>
</extensions>
</system.serviceModel>
</configuration>
L'extension peut être référencée à partir des liaisons personnalisées pour utiliser UDP comme transport.
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding configurationName="UdpCustomBinding">
<udpTransport/>
</binding>
</customBinding>
</bindings>
</system.serviceModel>
</configuration>
Section de liaison
La section ``SampleProfileUdpBindingCollectionElement
est un StandardBindingCollectionElement
qui expose SampleProfileUdpBinding
au système de configuration. Le bloc de l'implémentation est délégué à SampleProfileUdpBindingConfigurationElement
, qui dérive de StandardBindingElement
. SampleProfileUdpBindingConfigurationElement
a des propriétés qui correspondent à celles sur SampleProfileUdpBinding
, et des fonctions pour mapper à partir de la liaison ConfigurationElement
. Enfin, nous substituons OnApplyConfiguration
dans notre SampleProfileUdpBinding
, tel qu'indiqué dans l'exemple de code suivant.
protected override void OnApplyConfiguration(string configurationName)
{
if (binding == null)
throw new ArgumentNullException("binding");
if (binding.GetType() != typeof(SampleProfileUdpBinding))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
"Invalid type for binding. Expected type: {0}. Type passed in: {1}.",
typeof(SampleProfileUdpBinding).AssemblyQualifiedName,
binding.GetType().AssemblyQualifiedName));
}
SampleProfileUdpBinding udpBinding = (SampleProfileUdpBinding)binding;
udpBinding.OrderedSession = this.OrderedSession;
udpBinding.ReliableSessionEnabled = this.ReliableSessionEnabled;
udpBinding.SessionInactivityTimeout = this.SessionInactivityTimeout;
if (this.ClientBaseAddress != null)
udpBinding.ClientBaseAddress = ClientBaseAddress;
}
Pour enregistrer ce gestionnaire avec le système de configuration, nous ajoutons la section suivante au fichier de configuration approprié.
<configuration>
<configSections>
<sectionGroup name="system.serviceModel">
<sectionGroup name="bindings">
<section name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport />
</sectionGroup>
</sectionGroup>
</configSections>
</configuration>
Il pourra ensuite être référencé à partir de la section de configuration serviceModel.
<configuration>
<system.serviceModel>
<client>
<endpoint configurationName="calculator"
address="soap.udp://localhost:8001/"
bindingConfiguration="CalculatorServer"
binding="sampleProfileUdpBinding"
contract= "Microsoft.ServiceModel.Samples.ICalculatorContract">
</endpoint>
</client>
</system.serviceModel>
</configuration>
Client et service de test UDP
Le code de test permettant d'utiliser cet exemple de transport est disponible dans les répertoires UdpTestService et UdpTestClient. Le code de service se compose de deux tests : le premier définit les liaisons et les points de terminaison à partir du code, et le deuxième le fait via la configuration. Ces deux tests utilisent deux points de terminaison. Un point de terminaison utilise SampleUdpProfileBinding
avec <reliableSession> à la valeur true. L'autre utilise une liaison personnalisée avec UdpTransportBindingElement
. Cela revient à utiliser SampleUdpProfileBinding
avec <reliableSession> à la valeur false. Ces deux tests créent un service, ajoutent un point de terminaison pour chaque liaison, ouvrent le service, puis attendent que l'utilisateur tape ENTER avant de fermer le service.
Lorsque vous démarrez l'application de test de service, la sortie suivante doit s'afficher.
Testing Udp From Code.
Service is started from code...
Press <ENTER> to terminate the service and start service from config...
Vous pouvez ensuite exécuter l'application de test cliente sur les points de terminaison publiés. L'application de test cliente crée un client pour chaque point de terminaison et envoie cinq messages à chacun. Sortie sur le client :
Testing Udp From Imported Files Generated By SvcUtil.
0
3
6
9
12
Press <ENTER> to complete test.
Sortie complète sur le service :
Service is started from code...
Press <ENTER> to terminate the service and start service from config...
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
adding 0 + 0
adding 1 + 2
adding 2 + 4
adding 3 + 6
adding 4 + 8
Pour exécuter l'application cliente sur des points de terminaison publiés à l'aide de la configuration, tapez ENTER sur le service, puis exécutez de nouveau le client test. La sortie suivante doit s'afficher sur le service.
Testing Udp From Config.
Service is started from config...
Press <ENTER> to terminate the service and exit...
La réexécution du client génère les mêmes résultats que ceux obtenus précédemment.
Pour régénérer le code client et la configuration à l'aide de Svcutil.exe, démarrez l'application de service, puis exécutez le fichier Svcutil.exe suivant à partir du répertoire racine de l'exemple.
svcutil https://localhost:8000/udpsample/ /reference:UdpTranport\bin\UdpTransport.dll /svcutilConfig:svcutil.exe.config
Svcutil.exe ne générant pas de configuration d'extension de liaison pour SampleProfileUdpBinding
, vous devez donc l'ajouter manuellement.
<configuration>
<system.serviceModel>
…
<extensions>
<!-- This was added manually because svcutil.exe does not add this extension to the file -->
<bindingExtensions>
<add name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport" />
</bindingExtensions>
</extensions>
</system.serviceModel>
</configuration>
Pour configurer, générer et exécuter l'exemple
Pour générer la solution, suivez les instructions indiquées dans Génération des exemples Windows Communication Foundation.
Pour exécuter l'exemple dans une configuration à un ou plusieurs ordinateurs, suivez les instructions indiquées dans Exécution des exemples Windows Communication Foundation.
Référez-vous à la section « Client et service de test UDP » développée précédemment.
Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.