Je souhaite écrire un serveur en utilisant un pool de threads de travail et un port d'achèvement d'E/S. Le serveur doit traiter et transférer les messages entre plusieurs clients. Les données 'par client' sont dans une classe ClientContext. Les données entre les instances de cette classe sont échangées à l'aide des threads de travail. Je pense que c'est un scénario typique.IO Achèvement des ports: comment fonctionne WSARecv()?
Cependant, j'ai deux problèmes avec ces ports d'achèvement d'E/S.
(1) Le premier problème est que le serveur reçoit essentiellement des données des clients mais je ne sais jamais si un message complet a été reçu. En fait WSAGetLastError() renvoie toujours que WSARecv() est toujours en attente. J'ai essayé d'attendre l'événement OVERLAPPED.hEvent avec WaitForMultipleObjects(). Cependant, il bloque pour toujours, c'est-à-dire que WSARecv() ne se termine jamais dans mon programme. Mon but est d'être absolument sûr que tout le message a été reçu avant que le traitement ne commence. Mon message a un champ 'longueur de message' dans son en-tête, mais je ne vois pas vraiment comment l'utiliser avec les paramètres de la fonction IOCP. (2) Si WSARecv() est mis en commentaire dans l'extrait de code ci-dessous, le programme reçoit toujours des données. Qu'est-ce que ça veut dire? Cela signifie-t-il que je n'ai pas besoin d'appeler WSARecv() du tout? Je ne suis pas en mesure d'obtenir un comportement déterministe avec ces ports d'achèvement d'E/S. Merci pour votre aide!
while(WaitForSingleObject(module_com->m_shutdown_event, 0)!= WAIT_OBJECT_0)
{
dequeue_result = GetQueuedCompletionStatus(module_com->m_h_io_completion_port,
&transfered_bytes,
(LPDWORD)&lp_completion_key,
&p_ol,
INFINITE);
if (lp_completion_key == NULL)
{
//Shutting down
break;
}
//Get client context
current_context = (ClientContext *)lp_completion_key;
//IOCP error
if(dequeue_result == FALSE)
{
//... do some error handling...
}
else
{
// 'per client' data
thread_state = current_context->GetState();
wsa_recv_buf = current_context->GetWSABUFPtr();
// 'per call' data
this_overlapped = current_context->GetOVERLAPPEDPtr();
}
while(thread_state != STATE_DONE)
{
switch(thread_state)
{
case STATE_INIT:
//Check if completion packet has been posted by internal function or by WSARecv(), WSASend()
if(transfered_bytes > 0)
{
dwFlags = 0;
transf_now = 0;
transf_result = WSARecv(current_context->GetSocket(),
wsa_recv_buf,
1,
&transf_now,
&dwFlags,
this_overlapped,
NULL);
if (SOCKET_ERROR == transf_result && WSAGetLastError() != WSA_IO_PENDING)
{
//...error handling...
break;
}
// put received message into a message queue
}
else // (transfered_bytes == 0)
{
// Another context passed data to this context
// and notified it via PostQueuedCompletionStatus().
}
break;
}
}
}