2016-10-26 4 views
3

Ich rufe async_read auf einem Domain-Socket und mein Problem ist, dass ich manchmal Daten bekomme und manchmal nicht, obwohl das entfernte System immer Daten zurückgibt. Ich scheine in der Lage zu sein, von der Steckdose zu lesen, wenn ich Schritt-für-Schritt-Debugging mache. Wenn ich Komponententests automatisiere, scheinen sie zu schnell zu laufen, um Daten zurückzugeben, was merkwürdig ist, da der ganze Zweck von asynchronen Methoden darin besteht, auf eine Antwort zu warten.Heisenbug bei einem anyrronous lesen von Socket

ich diese als Eigenschaften meiner Klasse haben:

io_service run_loop; 
stream_protocol::socket connection_socket; 
datagram_protocol::endpoint domain_socket_ep; 
vector<unsigned char>read_buffer; 

ich einen Schreib:

void operator>>(const vector<unsigned char> input, shared_ptr<Socket>socket) { 
    asio::async_write(socket->connection_socket, asio::buffer(input), std::bind(&Socket::write_handler, socket, std::placeholders::_1, std::placeholders::_2)); 
    socket->run_loop.reset(); 
    socket->run_loop.run(); 
} 

Im Schreib Rückruf ich eine Lese:

void Socket::write_handler(const std::error_code &ec, const size_t size) noexcept { 
    const size_t avail = connection_socket.available(); 
    if (!read_buffer.empty()) { 
    read_buffer.clear(); 
    } 
    asio::async_read(connection_socket, asio::buffer(read_buffer, avail), std::bind(&Socket::read_handler, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 
} 

Ich habe versucht, Wrapping der Lesefunktion in einem while(read_buffer.size() < avail), aber das warf mich gerade in eine Endlosschleife.

Ich vermisse definitiv etwas hier, ich kann einfach nicht herausfinden, was und die Tatsache, dass das funktioniert, wenn man unter Schritt für Schritt läuft, macht es nur noch schlimmer.

+0

Was die zugewiesene Größe für ‚Input‘ und read_buffer? – Arunmu

+0

Die Eingabe wird vom Benutzer gesendet und ist in meinen Tests nie leer. read_buffer wird auf die Anzahl der Bytes im Socket gesetzt. – ruipacheco

Antwort

4

Auf der Leseseite der Dinge:

Sie erwähnen nie die Art von read_buffer. Es gibt nicht viel, was wir darüber wissen, was .clear() tut, aber wenn es das tut, was der Name schon sagt, wird es ungültig sein asio::buffer(read_buffer, avail) ohne

vor read_buffer.resize(avail)


zu verwenden Warum haben Sie

void operator>>(const vector<unsigned char> input, shared_ptr<Socket>socket) { 
    asio::async_write(socket->connection_socket, asio::buffer(input), std::bind(&Socket::write_handler, socket, std::placeholders::_1, std::placeholders::_2)); 
    socket->run_loop.reset(); 
    socket->run_loop.run(); 
} 

statt z.B

void operator>>(const std::vector<unsigned char> input, std::shared_ptr<Socket> socket) { 
    boost::system::error_code ec; 
    size_t transferred = boost::asio::write(socket->connection_socket, boost::asio::buffer(input), ec); 
    socket->write_handler(ec, transferred); 
} 

Wenn Sie keine asynchronen Operationen wünschen, verwenden Sie diese nicht. Das ist zumindest viel einfacher. Das folgende Beispiel würde SANE (wenn Sie sicherstellen, io lebt länger als jede Steckdose, die es verwendet):

Live On Coliru

#include <boost/asio.hpp> 

struct Socket { 
    boost::asio::io_service& svc; 
    boost::asio::ip::tcp::socket connection_socket; 

    Socket(boost::asio::io_service& svc) : svc(svc), connection_socket(svc) {} 

    void write_handler(boost::system::error_code ec, size_t bytes_transferred) { 
    } 
}; 

void operator>>(const std::vector<unsigned char> input, std::shared_ptr<Socket> socket) { 
    boost::system::error_code ec; 
    size_t transferred = boost::asio::write(socket->connection_socket, boost::asio::buffer(input), ec); 
    socket->write_handler(ec, transferred); 
} 

int main(){ 
    boost::asio::io_service io; 
    auto s = std::make_shared<Socket>(io); 

    std::vector<unsigned char> v { 100, 'a' }; 
    v >> s; 
} 
+0

meine Schreibvorgänge sind in Ordnung, es ist die Lesevorgänge, die fehlschlagen. read_buffer ist im ersten Codeblock definiert und schließlich möchte ich Async-Operationen. Warum sollte ich nicht? – ruipacheco

+1

Weil Sie sie nicht verwenden. Solange Sie einen einzigen 'io_service' mit einem Socket und' run() 'zum Abschluss haben, ist es effektiv synchron. Wenn Sie Asynchronität wünschen, ist die Lebensdauer des Vektors "input" völlig unzureichend. – sehe

+0

Nun, da ich die Definition von 'read_buffer' sehe, ist es in der Tat klar, dass der Fehler aufgetreten ist. Die Puffergröße ist 0, so dass alle Lesevorgänge einen Puffer mit Null Kapazität erhalten. – sehe