Envoi de la réponse asynchrone
Lorsque l’appel asynchrone est terminé, le serveur envoie une réponse au client en appelant la fonction RpcAsyncCompleteCall et en lui passant le handle asynchrone. Cet appel est nécessaire même si l’appel asynchrone a une valeur de retour void et [ aucun ] paramètre de sortie. Si la fonction a une valeur de retour, elle est passée par référence à RpcAsyncCompleteCall.
Quand le serveur appelle RpcAsyncCompleteCall ou RpcAsyncAbortCall, ou qu’un appel se termine parce qu’une exception a été levée dans la routine du gestionnaire de serveur, la bibliothèque Runtime RPC détruit automatiquement le handle asynchrone du serveur.
Notes
Le serveur doit terminer la mise à jour des [ paramètres in, out ] et [ out ] avant d’appeler RpcAsyncCompleteCall. Aucune modification ne peut être apportée à ces paramètres ou au handle asynchrone après l’appel de RpcAsyncCompleteCall. Si l’appel de fonction RpcAsyncCompleteCall échoue, le runtime RPC libère les paramètres.
L’exemple suivant illustre un appel de procédure asynchrone simple.
#define DEFAULT_ASYNC_DELAY 20;
#define ASYNC_CANCEL_CHECK 100;
void AsyncFunc(IN PRPC_ASYNC_STATE pAsync,
IN RPC_BINDING_HANDLE hBinding,
IN OUT unsigned long nAsychDelay)
{
int nReply = 1;
RPC_STATUS status;
unsigned long nTmpAsychDelay;
int i;
if (nAsychDelay < 0){
nAsychDelay = DEFAULT_ASYNC_DELAY;
}else if (nAsychDelay < 100){
nAsychDelay = 100;
}
// We only call RpcServerTestCancel if the call
// takes longer than ASYNC_CANCEL_CHECK ms
if(nAsychDelay > ASYNC_CANCEL_CHECK){
nTmpAsychDelay = nAsychDelay/100;
for (i = 0; i < 100; i++){
Sleep(nTmpAsychDelay);
if (i%5 == 0){
fprintf(stderr,
"\rRunning AsyncFunc (%lu ms) (%d%c) ... ",
nAsychDelay, i+5, PERCENT);
status =
RpcServerTestCancel(
RpcAsyncGetCallHandle(pAsync));
if (status == RPC_S_OK){
fprintf(stderr,
"\nAsyncFunc has been canceled!!!\n");
break;
}else if (status != RPC_S_CALL_IN_PROGRESS){
printf(
"RpcAsyncInitializeHandle returned 0x%x\n",
status);
exit(status);
}
}
}
}else{
Sleep(nAsychDelay);
}
printf("\nCalling RpcAsyncCompleteCall\n");
status = RpcAsyncCompleteCall(pAsync, &nReply);
printf("RpcAsyncCompleteCall returned 0x%x\n", status);
if (status){
exit(status);
}
}
Par souci de simplicité, cette routine de serveur asynchrone ne traite pas les données réelles. Il se met tout simplement en veille pendant un certain temps.
Notes
La fonction RpcAsyncCompleteCall peut être appelée sur le thread qui a reçu l’appel ou sur tout autre thread du processus. Si toutes les données nécessaires pour terminer l’appel sont immédiatement disponibles, le serveur peut les remplir sur le même thread et appeler RpcAsyncCompleteCall sur le même thread. Cette approche permet d’économiser un changement de contexte et d’améliorer les performances. De tels appels sont appelés associer façon opportuniste asynchrones.