2009-08-10 10 views
0

Ich habe ein Problem mit Asio. Meine Client/Server-Anwendung benötigt nur synchrone Kommunikation. Also, mit den Beispielen für Synchro von der Boost-Homepage habe ich zwei Prozeduren zum Senden und Empfangen von Daten eingerichtet. Ihr Code ist wie folgt:Boost.Asio synchrone Kommunikation

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; 
    }; 

Diese Verfahren sind nur Wrapper für die Codezeilen extrahiert aus den Boost-Beispielen.

In meinen Test-Anwendungen, ruft der Client

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

und der Server ruft

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

nur die Funktionalität zu testen. Das Problem ist, dass beide Anwendungen nach dem ersten Informationsaustausch einfrieren, wie ich in der folgenden picture dargestellt habe. Es scheint, dass vReceive() Prozedur auf der Client-Seite nicht abgeschlossen ist, während vSend() auf der Serverseite beendet. Also, hat jemand eine Idee, was könnte falsch sein?

Nur für den Fall, dass jemand das Problem replizieren wollte, habe ich die Sourcen komplette Quellen auf den gleichen Server hochgeladen, wo das Bild in der asio_problem.rar Datei ist (Ich kann einen Hyperlink pro Post als neues Mitglied haben).

Vielen Dank im Voraus, Daniel.

Antwort

1

Ich denke, Ihr Problem liegt hier:

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 */ 
} 

Du Looping unendlich, bis die Verbindung geschlossen wird (den einzigen Weg aus der Schleife zu brechen, wenn Sie einen EOF Fehler aus der Steckdose erhalten), aber vSend schließt nie den Sockel. Dies bedeutet, dass vReceive in Ihrem Client für immer wartet und immer mehr Daten erwartet. Putting ein socket.close() in vSend sollte den Trick gut machen.

Dies bedeutet natürlich, dass Ihr Client und Server den Socket nach jedem entsprechenden Aufruf von vReceive und vSend erneut öffnen müssen. Wenn das nicht erwünscht ist, empfehle ich andere Mittel, mit denen der Absender dem Empfänger mitteilt, dass keine Daten mehr gesendet werden.

Ich bin nicht sicher, ob Sie irgendwelche Beschränkungen für die Daten haben, die über die Leitung gesendet werden, aber entweder einen "Datenlänge" -Wert am Anfang Ihrer Nachricht oder eine Art "Ende der Daten" sentinel senden Wert am Ende würde Ihnen einen schönen, sauberen Indikator geben, wann Sie aufhören sollten, auf mehr Daten zu hören.

Dieser Ansatz hat den zusätzlichen Vorteil, dass Sie Grund haben, die read_until (oder ähnliche) Funktionalität von ASIO zu verwenden, um die Logik des Wartens auf das Ende der Daten für Sie zu handhaben.