boost::asio und socket read mit timeout



  • Hiho,

    ich nutze boost asio für Socketkommunikation und will den Fall abfangen, wenn die Verbindung hart unterbrochen wurde. Nach etwas suchen bin ich nun darauf gestoßen, dass ein Workaround dafür ein asynchrones Read mit Timeout ist.

    Nun habe ich etwas herumgespielt und getestet. Mein Problem ist nun, dass der read-Handler NIE aufgerufen wird, obwohl die Gegenseite etwas geschickt hat. Woran das liegt, kann ich mir nicht erklären. Evtl. sieht jemand den Fehler in meinem Code oder hat andere Vorschläge.

    //
    		inline void timeoutHandler(const boost::system::error_code& error,bool& wasCalled) 
    		{ 
    			//errorOut = error;
    			wasCalled = true;
    		}
    
    		//
    		inline void socketReadHandler(const boost::system::error_code& error, std::size_t size,boost::system::error_code& errorOut,std::size_t& sizeOut,bool& wasCalled)
    		{ 
    			errorOut = error;
    			sizeOut  = size;
    			wasCalled = true;
    		}
    
    		// Returns true if successful
    		inline bool getContentFromSocketNonBlocking(boost::asio::ip::tcp::socket& sock, std::string& buffer, std::string* pErrorMsg = 0)
    		{
    			//read buffer object
    			boost::asio::streambuf buf;
    
    			//error code
    			boost::system::error_code ec = boost::asio::error::would_block;
    			bool wasCalled = false;
    
    			//init async socket read
    			std::size_t read_size;
    			boost::asio::async_read(sock,buf,boost::bind(socketReadHandler, _1, _2, boost::ref(ec), boost::ref(read_size),boost::ref(wasCalled)));
    
    			//init async timer			
    			boost::asio::deadline_timer timer(sock.get_io_service()); 
    			timer.async_wait(boost::bind(timeoutHandler, _1, boost::ref(wasCalled)));
    			timer.expires_from_now(boost::posix_time::milliseconds(500));
    
    			// block until the asynchronous operation has completed.
    			sock.get_io_service().reset();
    			do sock.get_io_service().run_one(); while (!wasCalled);			
    
    			//timer expired?
    			if (ec == boost::asio::error::would_block) return true;
    
    			//socket read error?
    			if (ec)
    			{
    				if (pErrorMsg) *pErrorMsg = ec.message();
    
    				return false;
    			}
    
    			//convert buffer so string
    			std::istream is(&buf);
    			std::string::size_type index = buffer.size();
    			buffer.resize(buffer.size() + read_size);
    			is.read(&buffer[index],read_size);			
    
    			return true;
    
    		}
    


  • Also async_read liest in deinem Fall, bis der streambuf voll ist, also meldet sich erst dann beim Handler. Könnte es sein, dass der streambuf so groß ist, dass in den 500ms nicht genug Daten ankommen?
    Edit: Hast Du mal async_read_some ausprobiert?



  • Bist du da sicher? Dem Streambuffer geb ich keine größe vor, der wächst ja an sich dynamisch. Beim blockierendem LEsen nutz ich den auch immer und hatte damit nie Probleme.



  • Warum sollte er sich, nach der Logik, dann überhaupt mal bei deinem Handler melden, bevor man cancel drückt? Nach irgendeiner Menge von Bytes muss doch asio mal entscheiden, dass jetzt Zeit ist, den Handler aufzurufen. Und normalerweise ist das halt, wenn der Lesepuffer voll ist. Async_read_some hinhegegen meldet sich sofort, mit der maximalen Menge der lesbaren Bytes in dem Moment.
    Verstehe mich nicht falsch, ich bin mir keineswegs sicher, aber Du lieferst keinen kompilierbaren Code, mit dem man mal rumspielen könnte, daher tippe ich einfach ins Blaue. Der Rest sieht ja, soweit ich das beurteilen kann, funktionabel aus.



  • Decimad schrieb:

    Warum sollte er sich, nach der Logik, dann überhaupt mal bei deinem Handler melden, bevor man cancel drückt?

    Der Handler sollte ausgelöst werden, sobald irgendwelche Daten da sind. Beim synchronen Read funkioniert das ja genauso.

    VG

    Pellaeon



  • Ich habe halt noch nie mit boost::asio::streambuf gearbeitet. Ich benutze immer fixed-size-puffer und da komme ich ohne async_read_some nicht weit. Wenn Du Dir 100%ig sicher bist, dass da bei Dir keine versteckte 512-Byte Granularität oder soetwas ähnliches eingebaut ist, fällt mir nix mehr ein.


Anmelden zum Antworten