Cet article a fait l'objet d'une traduction automatique.
Programmation asynchrone
Sockets TCP asynchrones, une alternative à WCF
Dans un environnement de technologies Microsoft, à l'aide de Windows Communication Foundation (WCF) est une approche commune pour la création d'un système client-serveur. Il existe de nombreuses alternatives à WCF, bien sûr, chacun avec ses propres avantages et inconvénients, y compris les Services HTTP Web, Web API, DCOM, technologies Web AJAX, nommé une programmation tuyau et raw TCP socket. Mais si l'on tient compte de facteurs tels que l'effort de développement, de gestion, évolutivité, performances et sécurité, dans de nombreuses situations à l'aide de WCF est l'approche la plus efficace.
Toutefois, WCF peut être extrêmement complexe et pourrait être exagéré pour certaines situations de programmation. Avant la sortie de Microsoft .NET Framework 4.5, programmation socket asynchrone a été, à mon avis, trop difficile, le plus souvent pour justifier son utilisation. Mais la facilité d'utilisation le nouveau langage c# vous attendent et les fonctionnalités de langage async modifie l'équilibre, l'utilisation de la programmation de socket pour les systèmes client-serveur asynchrone est donc maintenant une option plus attrayante que l'habitude d'être. Cet article explique comment utiliser ces nouvelles fonctionnalités asynchrones de la .NET Framework 4.5 pour créer un bas niveau, haute -systèmes de logiciels client-serveur asynchrone performance.
Le meilleur moyen de voir où je veux en venir est de prendre un regard sur le système client-serveur de démo montré Figure 1. En haut de l'image un interpréteur de commandes est en cours d'exécution un TCP basée sur le socket service asynchrone qui accepte les demandes pour calculer la moyenne ou au moins un ensemble de valeurs numériques. Dans la partie centrale de l'image est une application Windows Forms (WinForm) qui a envoyé une demande de calculer la moyenne de (3, 1, 8). Notez que le client est asynchrone — après que la demande est envoyée, en attendant que le service de répondre, l'utilisateur a la possibilité de cliquer sur le bouton intitulé Say Hello trois fois, et la demande est recevable.
Figure 1 démo basé sur TCP Service avec deux Clients
La partie inférieure du Figure 1 montre un client d'application Web en action. Le client a envoyé une demande asynchrone pour trouver la valeur minimale (5, 2, 7, 4). Bien qu'il ne ressort pas de la capture d'écran, pendant que l'application Web attend la réponse du service, l'application est sensible aux entrées d'utilisateur.
Dans les sections qui suivent, je vais montrer comment coder le service, le client WinForm et l'application Web. En chemin, j'aborderai les avantages et les inconvénients de l'utilisation de sockets. Cet article suppose que vous avez au moins au niveau intermédiaire de programmation c# habileté, mais n'assume pas que vous avez connaissance approfondie ou une expérience significative avec la programmation asynchrone. Le téléchargement de code qui accompagne cet article a le code source complet pour les trois programmes contenus dans Figure 1. J'ai enlevé la vérification des erreurs plus normale pour garder les idées principales et aussi clair que possible.
Création du service
La structure globale du service démo, avec quelques modifications mineures pour économiser l'espace, est présentée en Figure 2. Pour créer le service, j'ai lancé Visual Studio 2012, qui a le requis .NET Framework 4.5 et a créé une nouvelle application de console c# nommée DemoService. Parce que les services basés sur le socket tendent à avoir des fonctionnalités spécifiques et limitées, à l'aide d'un nom plus descriptif serait préférable dans un scénario réel.
Figure 2 la Structure de programme de Service de démo
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading.Tasks;
namespace DemoService
{
class ServiceProgram
{
static void Main(string[] args)
{
try
{
int port = 50000;
AsyncService service = new AsyncService(port);
service.Run();
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
public class AsyncService
{
private IPAddress ipAddress;
private int port;
public AsyncService(int port) { .
.
}
public async void Run() { .
.
}
private async Task Process(TcpClient tcpClient) { .
.
}
private static string Response(string request)
private static double Average(double[] vals) { .
.
}
private static double Minimum(double[] vals) { .
.
}
}
}
Après le code du modèle chargé dans l'éditeur, j'ai modifié l'utilisation des déclarations en haut du code source à inclure System.Net et System.Net.Sockets. Dans la fenêtre de l'Explorateur de solutions, j'ai renommé le fichier Program.cs à ServiceProgram.cs et Visual Studio renommé automatiquement la classe Program pour moi. Démarrage du service est simple :
int port = 50000;
AsyncService service = new AsyncService(port);
service.Run();
Chaque service personnalisée basée sur le socket sur un serveur doit utiliser un port unique. Les numéros de port entre 49152 et 65535 sont généralement utilisés pour des services personnalisés. En évitant les collisions numéros de port peut être délicat. Il est possible de réserver des numéros de port sur un serveur utilisant le registre de système ReservedPorts entrée. Le service utilise une conception de programmation orientée objet (POO) et est instancié via un constructeur qui accepte le numéro de port. Parce que le service numéros de port sont fixes, le numéro de port peut être codé en dur plutôt que passé comme un paramètre. La méthode Run contient un certain temps boucle qui va accepter et traiter les demandes des clients jusqu'à ce que la coque de la console reçoit un < entrez > sur une touche.
La classe AsyncService a deux membres privés, adresse IP et le port. Ces deux valeurs définissent essentiellement une prise de courant. Le constructeur accepte un numéro de port et par programme détermine l'adresse IP du serveur. Méthode publique Run fait tout le travail d'acceptation des demandes, puis informatique et envoi des réponses. La méthode Run appelle la méthode d'assistance processus qui appelle à son tour d'assistance réponse. Réponse de méthode appelle aides moyenne et Minimum.
Il existe de nombreuses façons d'organiser un serveur socket. La structure utilisée dans la démo essaie de trouver un équilibre entre la modularité et la simplicité et a bien fonctionné pour moi dans la pratique.
Le constructeur de Service et les méthodes d'exécution
Les deux méthodes publiques du service basée sur le socket démo sont présentés en Figure 3. Après avoir mémorisé le nom de port, le constructeur utilise la méthode GetHostName pour déterminer le nom du serveur et ensuite chercher une structure qui contient des informations sur le serveur. La collection de l'objet AddressList possède machine différentes adresses, y compris IPv4 et IPv6. La valeur enum InterNetwork signifie une adresse IPv4.
Figure 3 constructeur de Service et les méthodes d'exécution
public AsyncService(int port)
{
this.port = port;
string hostName = Dns.GetHostName();
IPHostEntry ipHostInfo = Dns.GetHostEntry(hostName);
this.ipAddress = null;
for (int i = 0; i < ipHostInfo.AddressList.Length; ++i) {
if (ipHostInfo.AddressList[i].AddressFamily ==
AddressFamily.InterNetwork)
{
this.ipAddress = ipHostInfo.AddressList[i];
break;
}
}
if (this.ipAddress == null)
throw new Exception("No IPv4 address for server");
}
public async void Run()
{
TcpListener listener = new TcpListener(this.ipAddress, this.port);
listener.Start();
Console.Write("Array Min and Avg service is now running"
Console.WriteLine(" on port " + this.port);
Console.WriteLine("Hit <enter> to stop service\n");
while (true) {
try {
TcpClient tcpClient = await listener.AcceptTcpClientAsync();
Task t = Process(tcpClient);
await t;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
}
}
Cette approche limite le serveur pour écouter les requêtes en utilisant uniquement l'adresse du serveur premier assigné IPv4. Une alternative plus simple pourrait permettre au serveur d'accepter des demandes envoyées à l'une de ses adresses en assignant simplement le champ membre comme this.ipAddress = IPAddress.Any.
Avis du service exécuter la signature de méthode utilise le modificateur async, indiquant que dans le corps de la méthode une méthode asynchrone s'appellera en conjonction avec le mot-clé await. La méthode retourne void plutôt que la tâche plus habituelle parce que Run est appelé par la méthode Main, qui, comme un cas particulier, ne permet pas le modificateur async. Une alternative consiste à définir la méthode Run pour retourner le type de tâche et puis appelez la méthode comme service.Run().Attendre.
Le service de courir méthode instancie un objet TcpListener en utilisant le numéro de port et l'adresse IP du serveur. Méthode Start de l'auditeur commence à surveiller le port spécifié, en attente d'une demande de connexion.
À l'intérieur de la principale de traitement tout en boucle, un objet de TcpClient, que vous pouvez considérer comme une prise intelligente, est créé et attend une connexion via la méthode AcceptTcpClientAsync. Avant le .NET Framework 4.5, vous devrez utiliser BeginAcceptTcpClient et puis écrire de code personnalisé coordination asynchrone qui, croyez-moi, n'est pas simple. Le .NET Framework 4.5 ajoute de nombreuses nouvelles méthodes qui, par convention, se terminent par « Async ». Ces nouvelles méthodes, combiné avec l'async et attendent des mots-clés, rendre la programmation asynchrone beaucoup plus facile.
Exécution de méthode appelle la méthode processus à l'aide de deux instructions. Une alternative consiste à utiliser la syntaxe de raccourci et appelez la méthode processus dans une seule instruction : attendre Process(tcpClient).
Pour résumer, le service utilise des objets TcpListener et TcpClient pour masquer la complexité de la programmation de socket raw et utilise la nouvelle méthode AcceptTcpClientAsync conjointement avec le nouveau async et attendre les mots-clés pour masquer la complexité de la programmation asynchrone. Méthode Run définit et coordonne les activités de la connexion et appelle la méthode processus pour traiter les demandes, puis une deuxième déclaration d'attendre sur la tâche de retour.
Le processus du Service et les méthodes d'intervention
Les méthodes de processus et de la réponse de l'objet de service sont présentés à Figure 4. Signature de la méthode le processus utilise le modificateur async et retourne le type tâche.
Figure 4 la démo Service processus et méthodes d'intervention
private async Task Process(TcpClient tcpClient)
{
string clientEndPoint =
tcpClient.Client.RemoteEndPoint.ToString();
Console.WriteLine("Received connection request from "
+ clientEndPoint);
try {
NetworkStream networkStream = tcpClient.GetStream();
StreamReader reader = new StreamReader(networkStream);
StreamWriter writer = new StreamWriter(networkStream);
writer.AutoFlush = true;
while (true) {
string request = await reader.ReadLineAsync();
if (request != null) {
Console.WriteLine("Received service request: " + request);
string response = Response(request);
Console.WriteLine("Computed response is: " + response + "\n");
await writer.WriteLineAsync(response);
}
else
break; // Client closed connection
}
tcpClient.Close();
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
if (tcpClient.Connected)
tcpClient.Close();
}
}
private static string Response(string request)
{
string[] pairs = request.Split('&');
string methodName = pairs[0].Split('=')[1];
string valueString = pairs[1].Split('=')[1];
string[] values = valueString.Split(' ');
double[] vals = new double[values.Length];
for (int i = 0; i < values.Length; ++i)
vals[i] = double.Parse(values[i]);
string response = "";
if (methodName == "average") response += Average(vals);
else if (methodName == "minimum") response += Minimum(vals);
else response += "BAD methodName: " + methodName;
int delay = ((int)vals[0]) * 1000; // Dummy delay
System.Threading.Thread.Sleep(delay);
return response;
}
Un des avantages de l'utilisation de sockets de bas niveau au lieu de Windows Communication Foundation (WCF) est que vous pouvez facilement insérer des instructions WriteLine diagnostiques n'importe où que vous choisissez. Dans la démo, j'ai remplacé clientEndPoint avec la valeur factice de l'adresse IP 123.45.678.999 pour des raisons de sécurité.
Les trois lignes principales en méthode processus sont :
string request = await reader.ReadLineAsync();
...
string response = Response(request);
...
await writer.WriteLineAsync(response);
Vous pouvez interpréter la première instruction signifie, « lire une ligne de la demande de façon asynchrone, permettant aux autres instructions à exécuter si nécessaire. » Une fois que la chaîne de requête est obtenue, il est passé à l'aide de la réponse. Alors la réponse est envoyée au client demandeur de façon asynchrone.
Le serveur utilise un cycle d'écriture-réponse-requête, de la lecture. C'est simple, mais il y a plusieurs mises en garde dont vous devez être conscient. Si le serveur lit sans écriture, il ne peut pas détecter une situation semi-ouvertes. Si le serveur écrit sans les lire (par exemple, répondre avec une grande quantité de données), il pourrait se bloquer avec le client. Une conception de la lecture-écriture est acceptable pour des prestations propres simples mais ne doit pas être utilisée pour des services qui sont critiques ou au public.
La méthode de réponse accepte la chaîne de requête, analyse la demande et calcule une chaîne de réponse. Une résistance simultanée et la faiblesse d'un service basée sur le socket est que vous devez artisanat une sorte de protocole personnalisé. Dans ce cas, les demandes sont censés pour ressembler à :
method=average&data=1.1 2.2 3.3&eor
En d'autres termes, le service attend le littéral "méthode =" suivie de la « moyenne » de la chaîne ou "minimale", puis une esperluette (« & ») suivi par le littéral "données =". Les données d'entrée doivent être sous forme délimitée par des espaces. La demande se termine par un « & » suivie par le littéral « rap », qui est synonyme de fin-de-demande. Un inconvénient des services basés sur le socket comparée à WCF est que la sérialisation de types de paramètres complexes peut être à un peu difficile parfois.
Dans cet exemple de démo, la réponse est simple, juste une chaîne représentant la moyenne ou au moins un tableau de valeurs numériques. Dans de nombreuses situations de client-serveur personnalisé, vous devrez concevoir un protocole pour la réponse du service. Par exemple, au lieu d'envoyer une réponse tout aussi "4,00", vous pouvez envoyer la réponse comme "moyenne = 4.00. »
Méthode processus utilise une approche relativement grossière pour fermer une connexion si une Exception se produit. Une alternative consiste à utiliser le c# à l'aide de la déclaration (qui se ferment automatiquement n'importe quelle connexion) et supprimer l'appel explicite à la méthode fermer.
Méthodes d'assistance moyenne et Minimum sont définis comme :
private static double Average(double[] vals)
{
double sum = 0.0;
for (int i = 0; i < vals.Length; ++i)
sum += vals[i];
return sum / vals.Length;
}
private static double Minimum(double[] vals)
{
double min = vals[0]; ;
for (int i = 0; i < vals.Length; ++i)
if (vals[i] < min) min = vals[i];
return min;
}
Dans la plupart des situations, si vous utilisez une structure de programme similaire pour le service de démo, vos méthodes d'assistance à ce stade seraient se connecter à une source de données et extraire des données. Un avantage des services de bas niveau, c'est que vous avez plus de contrôle sur votre approche de l'accès aux données. Par exemple, si vous obtenez des données de SQL, vous pouvez utiliser classique ADO.NET, le Entity Framework ou toute autre méthode d'accès aux données.
Des inconvénients d'une approche de bas niveau est que vous devez explicitement déterminer comment gérer les erreurs dans votre système. Ici, si le service de démo est impossible d'analyser correctement la chaîne de requête, au lieu de retourner une réponse valide (sous forme de chaîne), le service retourne un message d'erreur. Selon mon expérience, il y a très peu de principes généraux sur lesquels s'appuyer. Chaque service requiert la gestion des erreurs personnalisée.
Notez que la méthode de réponse dispose d'un délai factice :
int delay = ((int)vals[0]) * 1000;
System.Threading.Thread.Sleep(delay);
Ce retard de réponse, arbitrairement basé sur la première valeur numérique de la demande, a été inséré afin de ralentir le service afin que les clients d'application WinForm et Web a peuvent démontrer la réactivité de l'interface utilisateur pendant que vous attendez une réponse.
Le Client de démo d'Application WinForm
Pour créer le client WinForm montré Figure 1, j'ai lancé Visual Studio 2012 et créé une application WinForm c# nommée DemoFormClient. Notez que, par défaut, Visual Studio modularizes une application WinForm en plusieurs fichiers qui séparent le code d'interface utilisateur à partir du code de la logique. Pour le téléchargement de code qui accompagne cet article, j'ai refactorisé le code de Visual Studio par modules dans un fichier de code source unique. Vous pouvez compiler l'application en lançant un interpréteur de commandes de Visual Studio (qui sait où le compilateur c# est) et en exécutant la commande : / target : winexe CSC.exe DemoFormClient.cs.
Grâce aux outils de conception de Visual Studio , j'ai ajouté un contrôle ComboBox, un contrôle TextBox, deux contrôles Button et un contrôle ListBox, ainsi que quatre contrôles Label. Pour le contrôle ComboBox, j'ai ajouté des cordes « moyennes » et « minimum » à la propriété de collection Items du contrôle. J'ai changé les propriétés Text de bouton1 et Bouton2 à envoyer Async et Say Hello, respectivement. Ensuite, en mode design, j'ai double-cliqué sur le contrôle button1 et button2 d'enregistrer leurs gestionnaires d'événements. J'ai édité les gestionnaires de clic, comme le montre Figure 5.
Figure 5 WinForm démo Client bouton Click des gestionnaires
private async void button1_Click(object sender, EventArgs e)
{
try {
string server = "mymachine.
network.microsoft.com";
int port = 50000;
string method = (string)comboBox1.SelectedItem;
string data = textBox1.Text;
Task<string> tsResponse =
SendRequest(server, port, method, data);
listBox1.Items.Add("Sent request, waiting for response");
await tsResponse;
double dResponse = double.Parse(tsResponse.Result);
listBox1.Items.Add("Received response: " +
dResponse.ToString("F2"));
}
catch (Exception ex) {
listBox1.Items.Add(ex.Message);
}
}
private void button2_Click(object sender, EventArgs e)
{
listBox1.Items.Add("Hello");
}
Remarquez que la signature du gestionnaire click du contrôle button1 a été modifiée pour inclure le modificateur async. Le gestionnaire met en place un nom codé en dur de l'ordinateur serveur comme un numéro de port et de la chaîne. Lorsque vous utilisez des services bas niveau basée sur le socket, il n'y a aucun mécanisme de découverte automatique et si les clients doivent avoir accès pour le nom du serveur ou les informations de port et l'adresse IP.
Les principales lignes de code sont :
Task<string> tsResponse = SendRequest(server, port, method, data);
// Perform some actions here if necessary
await tsResponse;
double dResponse = double.Parse(tsResponse.Result);
SendRequest est une méthode asynchrone définie par programme. L'appel peut être librement interprété comme « envoyer une demande asynchrone qui retourne une chaîne et lorsque vous avez terminé continuer l'exécution à l'instruction « attendent tsResponse, » qui se produit plus tard. » Cela permet à l'application effectuer d'autres actions pendant que vous attendez la réponse. Parce que la réponse est encapsulée dans une tâche, le résultat de la chaîne réelle doit être extrait à l'aide de la propriété Result. Ce résultat de chaîne est converti en type double de sorte qu'il peut être bien formatée avec deux décimales.
Une approche alternative de l'appel est :
string sResponse = await SendRequest(server, port, method, data);
double dResponse = double.Parse(sResponse);
listBox1.Items.Add("Received response: " + dResponse.ToString("F2"));
Ici, le mot clé await est placé en ligne avec l'appel asynchrone à SendRequest. Cela simplifie le code appelant un peu et autorise également la chaîne de retour doivent être extraites sans un appel à Task.Result. Le choix d'utiliser une ligne attendent des appels ou en utilisant un appel distinct-déclaration await variera de la situation à la situation, mais comme une règle générale, il est préférable d'éviter l'utilisation explicite de la propriété Result de l'objet d'une tâche.
L'essentiel du travail asynchrone est effectuée dans l'envoyerdemande méthode, qui est répertorié dans Figure 6. SendRequest étant asynchrone, il peut mieux être nommé SendRequestAsync ou MySendRequestAsync.
Figure 6 WinForm démo Client SendRequest, méthode
private static async Task<string> SendRequest(string server,
int port, string method, string data)
{
try {
IPAddress ipAddress = null;
IPHostEntry ipHostInfo = Dns.GetHostEntry(server);
for (int i = 0; i < ipHostInfo.AddressList.Length; ++i) {
if (ipHostInfo.AddressList[i].AddressFamily ==
AddressFamily.InterNetwork)
{
ipAddress = ipHostInfo.AddressList[i];
break;
}
}
if (ipAddress == null)
throw new Exception("No IPv4 address for server");
TcpClient client = new TcpClient();
await client.ConnectAsync(ipAddress, port); // Connect
NetworkStream networkStream = client.GetStream();
StreamWriter writer = new StreamWriter(networkStream);
StreamReader reader = new StreamReader(networkStream);
writer.AutoFlush = true;
string requestData = "method=" + method + "&" + "data=" +
data + "&eor"; // 'End-of-request'
await writer.WriteLineAsync(requestData);
string response = await reader.ReadLineAsync();
client.Close();
return response;
}
catch (Exception ex) {
return ex.Message;
}
}
SendRequest accepte une chaîne représentant le nom du serveur et commence par résoudre ce nom à une adresse IP en utilisant la même logique de code qui a été utilisée dans le constructeur de classe de service. Une alternative plus simple est de passer juste le nom du serveur : attendent le client.ConnectAsync (serveur, port).
Adresse IP du serveur est déterminé, un TcpClient intelligent-socket objet est instancié et l'objet de Connectméthode Async est utilisé pour envoyer une demande de connexion au serveur. Après avoir configuré un objet StreamWriter de réseau pour envoyer des données vers le serveur et un objet StreamReader pour recevoir des données depuis le serveur, une chaîne de requête est créée en utilisant le format attendu par le serveur. La demande est envoyée et reçue de façon asynchrone, retournée par la méthode sous forme de chaîne.
Application Web démo Client
J'ai créé le client d'application de Web démo montré Figure 1 en deux étapes. Tout d'abord, j'ai utilisé Visual Studio pour créer un site Web pour héberger l'application, et puis j'ai codé l'application Web en utilisant le bloc-notes. J'ai lancé Visual Studio 2012 et créé un nouveau Site Web vide c# nommée DemoClient à http://localhost/. Cet ensemble tous l'IIS nécessaires pour héberger une application de plomberie et créé l'emplacement physique associé au site Web à C:\inetpub\wwwroot\DemoClient\. Le processus a également créé un fichier de configuration de base, fichier Web.config, qui contient des informations qui permettent aux applications du site à la fonctionnalité d'accès asynchrone dans le .NET Framework 4.5 :
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="false" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
</configuration>
Ensuite, j'ai lancé le bloc-notes avec des privilèges d'administrateur. Lorsque vous créez des applications ASP.NET simples, je préfère parfois l'aide du bloc-notes au lieu de Visual Studio donc je peux garder tous les code de l'application dans un fichier .aspx unique, plutôt que de générer plusieurs fichiers et non désirés d'exemple de code. J'ai sauvé le fichier vide comme DemoWebClient.aspx à C:\inetpub\wwwroot\DemoClient.
La structure globale de l'application Web s'affiche dans Figure 7.
Figure 7 Web Application démo Client Structure
<%@ Page Language="C#" Async="true" AutoEventWireup="true"%>
<%@ Import Namespace="System.Threading.Tasks" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="System.Net.Sockets" %>
<%@ Import Namespace="System.IO" %>
<script runat="server" language="C#">
private static async Task<string> SendRequest(string server,
private async void Button1_Click(object sender, System.EventArgs e) { .
.
}
</script>
<head>
<title>Demo</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p>Enter service method:
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox></p>
<p>Enter data:
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox></p>
<p><asp:Button Text="Send Request" id="Button1"
runat="server" OnClick="Button1_Click"> </asp:Button> </p>
<p>Response:
<asp:TextBox ID="TextBox3" runat="server"></asp:TextBox></p>
<p>Dummy responsive control:
<asp:TextBox ID="TextBox4" runat="server"></asp:TextBox></p>
</div>
</form>
</body>
</html>
En haut de la page, j'ai ajouté les instructions Import pour amener les espaces de noms .NET pertinents dans la portée, ainsi qu'une directive de Page qui inclut le Async = true attribut.
La région de script c# contient deux méthodes SendRequest et Button1_Click. Le corps de page demande a deux contrôles TextBox et un contrôle Button pour l'entrée, une sortie TextBox contrôle pour maintenir la réponse de service et un contrôle TextBox factice, non utilisé pour démontrer la réactivité de l'interface utilisateur lorsque l'application attend pour le service répondre à une demande.
Le code de méthode SendRequest de l'application Web est exactement le même que le code Send de l'application WinFormdemander. Le code pour le gestionnaire Button1_Click de l'application Web ne diffère que légèrement de gestionnaire button1_Click de la WinForm pour tenir compte de l'interface utilisateur différente :
try {
string server = "mymachine.
network.microsoft.com";
int port = 50000;
string method = TextBox1.Text;
string data = TextBox2.Text;
string sResponse = await SendRequest(server, port, method, data);
double dResponse = double.Parse(sResponse);
TextBox3.Text = dResponse.ToString("F2");
}
catch (Exception ex) {
TextBox3.Text = ex.Message;
}
Même si le code de l'application Web est essentiellement le même que le code d'application WinForm, le mécanisme de l'appelant est un peu différent. Lorsqu'un utilisateur fait une demande en utilisant le WinForm, le WinForm émet l'appel directement au service et le service traite directement le WinForm. Lorsqu'un utilisateur effectue une demande de l'application Web, l'application Web envoie les informations au serveur Web qui héberge l'application, le serveur Web effectue l'appel au service, le service répond au serveur Web, le serveur Web génère une page de réponse qui inclut la réponse et la page de réponse est envoyée au navigateur client.
Synthèse
Alors, quand vous envisagez d'utiliser des sockets TCP asynchrones au lieu de WCF ? Environ 10 ans, avant la création de WCF et sa technologie de prédécesseur ASP.NET Web Services, si vous voulez créer un système client-serveur, utilisation de sockets a été souvent option la plus logique. L'introduction de WCF est une grande avancée, mais en raison de la multiplicité des scénarios que WCF est conçu pour gérer, l'utiliser pour les systèmes client-serveur simple pourrait être exagéré dans certaines situations. Bien que la dernière version de WCF est plus facile à configurer que les versions précédentes, il peut encore être difficile de travailler avec WCF.
Pour le cas où le client et le serveur sont sur différents réseaux, sécurité faisant une considération majeure, j'ai toujours utiliser WCF. Mais pour de nombreux systèmes client-serveur où le client et le serveur sont trouvent sur un réseau d'entreprise sécurisé unique, je préfère souvent à l'aide de sockets TCP.
Une approche relativement nouvelle pour la mise en œuvre des systèmes client-serveur consiste à utiliser le cadre de Web API ASP.NET pour les services basés sur HTTP combinés avec la bibliothèque de SignalR ASP.NET pour les méthodes asynchrones. Cette approche, dans de nombreux cas, est plus simple à mettre en œuvre qu'à l'aide de WCF et évite les nombreux détails bas niveau impliqués avec une approche de prise de courant.
Dr. James McCaffrey* travaille pour Microsoft Research à Redmond, Washington Il a travaillé sur plusieurs produits Microsoft, y compris Internet Explorer et Bing. Il peut être contacté à jammc@microsoft.com.*
Remercie les experts techniques suivants pour leurs conseils et relu cet article : Piali Choudhury (MS Research), Stephen Cleary (consultant), Adam Eversole (MS Research) Lynn pouvoirs (MS Research) et Stephen Toub (Microsoft)