2009-08-10 17 views
0

J'ai un problème avec asio. Mon application client/serveur nécessite uniquement une communication synchrone. Donc, en utilisant les exemples de synchro de la page d'accueil de boost, j'ai mis en place deux procédures pour envoyer et recevoir des données. Leur code est le suivant:Communication synchrone Boost.Asio

void vReceive(tcp::socket & socket, std::string & szDest){ 
    char szTmp_Buf [BUF_LEN + 1]; 
    szDest = ""; 
    std::cout << "Entering vReceive . . ." << std::endl; 

    for (;;){ 
     char szBuf [BUF_LEN]; 
     boost::system::error_code error; 
     uInt uiBytes_Recv = socket.read_some(boost::asio::buffer(szBuf), error); 
     std::cout << " Read " << uiBytes_Recv << " bytes" << std::endl; 
     if (error == boost::asio::error::eof) 
     break; // Connection closed cleanly by peer. 
     else if (error) 
     throw boost::system::system_error(error); // Some other error. 

     memcpy((void*) szTmp_Buf, (void*) szBuf, uiBytes_Recv); 
     szTmp_Buf[ uiBytes_Recv ] = '\0'; 
     szDest += szTmp_Buf; 
     }; 
     std::cout << "Received" << szDest << std::endl; 
     std::cout << "Leaving vReceive . . ." << std::endl << std::endl; 
    }; 

void vSend(tcp::socket & socket, std::string & szSrc){ 
    std::cout << "Entering vSend . . . " << std::endl; 
    std::cout << "Sending " << szSrc << std::endl; 
    boost::system::error_code ignored_error; 
    boost::asio::write(socket, boost::asio::buffer(szSrc), boost::asio::transfer_all(), ignored_error); 
    std::cout << "Leaving vSend . . . " << std::endl << std::endl; 
    }; 

Ces procédures ne sont que des enveloppes pour les lignes de code extraites des exemples d'amplification.

Dans mes applications de test, le client appelle

std::string szDate; 
vReceive(socket, szDate); 
vSend(socket, std::string("Chop Suey!")); 
vReceive(socket, szDate); 
vSend(socket, std::string("Halo")); 

et le serveur appelle

std::string message = make_daytime_string(); 
std::string szReceived; 
vSend(socket, message); 
vReceive(socket, szReceived); 
vSend(socket, message); 
vReceive(socket, szReceived); 

juste pour tester la fonctionnalité. Le problème est que les deux applications gèlent après le premier échange d'informations, comme je l'ai décrit sur le picture suivant. Il semble que la procédure vReceive() vReceive() côté client ne se termine pas tandis que vSend() se termine du côté serveur. Alors, quelqu'un a-t-il une idée, qu'est-ce qui pourrait être mauvais? Juste au cas où quelqu'un voudrait reproduire le problème, j'ai téléchargé les sources complètes sources sur le même serveur, où l'image est dans le fichier asio_problem.rar (je peux avoir un lien hypertexte par poste en tant que nouveau membre).

Merci d'avance, Daniel.

Répondre

1

Je pense que votre problème est ici:

for (;;){ 
    /* snipped */ 

    if (error == boost::asio::error::eof) 
    break; // Connection closed cleanly by peer. 
    else if (error) 
    throw boost::system::system_error(error); // Some other error. 

    /* snipped */ 
} 

Vous boucle indéfiniment jusqu'à ce que la ferme de connexion (la seule façon de sortir de la boucle est que si vous recevez une erreur EOF de la prise), mais vSend ne ferme jamais la prise. Cela signifie que vReceive dans votre client attendra toujours, en attendant toujours plus de données. Mettre un socket.close() dans vSend devrait faire l'affaire bien.

Bien sûr, cela signifie que votre client et votre serveur devront rouvrir le socket après chaque appel à vReceive et vSend. Si ce n'est pas souhaitable, alors je recommande d'utiliser d'autres moyens de l'expéditeur notifiant le récepteur que plus de données seront envoyées. Je ne suis pas sûr si vous avez des contraintes sur les données envoyées sur le fil, mais soit en envoyant une valeur de "longueur de données" au début de votre message ou une sorte de sentinelle de "fin de données" valeur à la fin vous donnerait un bon indicateur clair de quand cesser d'écouter pour plus de données.

Cette approche présente l'avantage supplémentaire de vous donner des raisons d'utiliser la fonctionnalité read_until (ou similaire) d'ASIO pour gérer la logique d'attente de la fin des données pour vous.