boost::asio::buffer Problem

11/11/2013 19:56 th0rex#1
Hello guys,

i am writing a private server in c++ and i searched a library for networking. Boost was referenced really often so i used it. Now i want to write something to the socket by using boost::asio::async_write(). The problem is that i need to concat 3 things. The first thing is a string the second thing an string and the third a string aswell. I tried this:
Code:
boost::asio::async_write(sock,boost::asio::buffer("RDY|I|" + x[1] +  "|Beta_Test|10|360|300000|300000|265000|265000|100|300|1000|1000|1|3|0|1500|900|15|0|1337|1337|21|1337|1337|1337|21|lol|3|2|0|50|25"),write_handler);
Where x[1] is a vector containing the userid as a string! which was optained by the package of a client.
It told me that there is no + operator so i searched how to concat things "into" a buffer. Google came up with something like this:
Code:
              std::vector<boost::asio::const_buffer> buffers;
			buffers.push_back(boost::asio::buffer("RDY|I|"));
			buffers.push_back(boost::asio::buffer(x[1]));
			buffers.push_back(boost::asio::buffer("|Beta_Test|10|360|300000|300000|265000|265000|100|300|1000|1000|1|3|0|1500|900|15|0|1337|1337|21|1337|1337|1337|21|lol|3|2|0|50|25"));

boost::asio::async_write(sock,boost::asio::buffer(buffers),write_handler);
Again x[1] is the userid.

The program compiles but as soon as it sends the package i get the following messagebox and i don't know what to do about it :

---------------------------
Microsoft Visual C++ Runtime Library
---------------------------
Debug Assertion Failed!

Program: C:\Windows\system32\MSVCP110D.dll
File: c:\program files (x86)\microsoft visual studio 11.0\vc\include\vector
Line: 72

Expression: vector iterator not dereferencable

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)

---------------------------
Abbrechen Wiederholen Ignorieren
---------------------------

I hope someone can help me about that.
11/11/2013 20:48 Omdi#2
Use std::stringstream to put all strings in one buffer and finally std::stringstream::str () in boost::asio::buffers constructor.
11/11/2013 21:13 th0rex#3
Tanks for the answer, i'll try tomorrow.
11/12/2013 12:56 Omdi#4
Okay habs mal auf dein Beispiel übertragen :p

Code:
#include <sstream>

//...

std::stringstream ss;

ss << "RDY|I|" << x[1] << "|Beta_Test|10|360|300000|300000|265000|265000|100|300|1000|1000|1|3|0|1500|900|15|0|1337|1337|21|1337|1337|1337|21|lol|3|2|0|50|25";

boost::asio::async_write(sock,boost::asio::buffer(ss.str()),write_handler);

//...
11/12/2013 13:53 th0rex#5
Edit :
Kriege jetzt :
---------------------------
Microsoft Visual C++ Runtime Library
---------------------------
Debug Assertion Failed!

Program: C:\Windows\system32\MSVCP110D.dll
File: c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring
Line: 79

Expression: string iterator not dereferencable

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)

---------------------------
Abbrechen Wiederholen Ignorieren
---------------------------
An etwas anderem im Code dürfte es eigentlich nicht liegen.
Hier trotzdem mal der komplette code:
Code:
cout<<"Creating stations...\n";	
boost::asio::async_write(sock,boost::asio::buffer("0|s|1|1|redStation|1|1500|1000|1000"),write_handler);	
boost::asio::async_write(sock,boost::asio::buffer("0|s|2|1|redStation|3|1500|15000|10000"),write_handler);
boost::asio::async_write(sock,boost::asio::buffer("0|s|3|1|redStation|4|1500|9000|9000"),write_handler);

cout<<"Creating npcs...\n";
boost::asio::async_write(sock,boost::asio::buffer("f|C|1|120|1|Test|1500|1500|0|3|1|0|3|0"),write_handler);

boost::asio::async_write(sock,boost::asio::buffer("0|CSS|1"),write_handler);
boost::asio::async_write(sock,boost::asio::buffer("0|SMP|1|1"),write_handler);
std::stringstream ss;
ss << "RDY|I|" << x[1] << "|Beta_Test|10|360|300000|300000|265000|265000|100|300|1000|1000|1|3|0|1500|900|15|0|1337|1337|21|1337|1337|1337|21|lol|3|2|0|50|25";

boost::asio::async_write(sock,boost::asio::buffer(ss.str()),write_handler);
Habe folgende header includet:
Code:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

#include <cstdlib>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
#include <boost/array.hpp> 
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>

#include "UserClass.h"
#include "Ship.h"
Weiß jetzt nicht ob das von bedeutung ist, habe aber folgende using direktiven (oder wie auch immer das hießt):
Code:
using std::cout;
using std::cin;
using std::string;
using boost::asio::ip::tcp;
11/13/2013 18:27 th0rex#6
Does no one has a Solution for it ._. ?
11/13/2013 23:06 Omdi#7
Sicher, dass x [1] valid ist?
Ich würd mal x.at (1) statt x [1] verwenden.

Uhm wenn die UserID in deinem vector vom Typ std::string ist, sollte es kein Problem sein den + operator zu benutzen um Strings miteinander zu verketten.
11/14/2013 06:23 th0rex#8
Werde ich nacher versuchen, danke für die Antwort.
Und valid müsste es sein.

Edit: Also x.at(1) geht auch nicht. Wenn ich den + Operator nutze kommt das selbe wie bei deiner Idee mit dem string Stream. Hier ist jetzt mal der Code wie Sachen in den vektor geschrieben werden:
Code:
string packetHeader = buffer.data();
std::vector<string> x = split(packetHeader,'|');
//... Verarbeitung ... Ganz viel If undso ...

//split function
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}


std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    split(s, delim, elems);
    return elems;
}
So das Packet hat folgenden aufbau :
LOGIN|UserId|SessionId|Version
Bsp: LOGIN|1001|12345678|4.1
Hoffe du kannst mir mit den Infos helfen :/ Wenn du mehr Infos brauchst, sag mir einfach was du brauchst.
11/14/2013 21:35 Omdi#9
Also so funktionierts aufjedenfall:
[Only registered and activated users can see links. Click Here To Register...]
11/15/2013 15:46 th0rex#10
Ja die userid bekomme ich auch. Ich kann auch einen neuen string machen und alles zusammen fügen oder den StringStream nutzen, aber bei dem senden wird mir immer gesagt
"Program: C:\Windows\system32\MSVCP110D.dll
File: c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring
Line: 79

Expression: string iterator not dereferencable"
Liegt es vielleicht daran das ich die asyn_write methode mit einem boost::asio::buffer aufrufe ? Gibt es vielleicht Wege direkt einen string zu übergeben ?
11/15/2013 16:11 Schlüsselbein#11
Wo genau tritt der Fehler denn auf? Schonmal den Debugger benutzt?
11/15/2013 16:17 th0rex#12
Habe das schon oft debuggt. Nur desto öfter ich das mache desto weniger verstehe ich es ._.
Edit : Ich weiß ehrlich gesagt nicht wo es sonst liegen soll. Hier ist mal der Code vom write_handler aber daran kann es eigentlich nicht liegen.
Code:
void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) 
{ 
	cout<<"Written: " << bytes_transferred << " bytes\n";
	cout<<"Waiting for other packets\n";
	buffer.assign(0); //ist boost::array<char,4096>.
	if(flag){
		flag = false;
		sock.close();
		cout << "Socket closed\n";
		acceptor.listen(); 
		acceptor.async_accept(sock, accept_handler); 
		//io_service.run(); 
	}
	else{
		sock.async_read_some(boost::asio::buffer(buffer), read_handler); 
	}
}
Also der Client Schickt nen request und erwartet eine antwort. Danach muss die connection geschlossen werden und eine neue aufgebaut werden. Aber den Code habe ich nie verändert und nur wenn ich das Packet mit dem zusammengesetztem string sende gibt es einen Fehler. Und das senden mache ich so :
Code:
string test2 = "RDY|I|" + x[1] + "|Beta_Test|10|360|300000|300000|265000|265000|100|300|1000|1000|1|3|0|1500|900|15|0|1337|1337|21|1337|1337|1337|21|lol|3|2|0|50|25";
boost::asio::async_write(sock,boost::asio::buffer(test2),write_handler);
11/15/2013 17:55 Tasiro#13
Du erstellst ein Objekt vom Typ std::string, welches am Ende seines Gültigkeitsbereiches zerstört wird.
In der [Only registered and activated users can see links. Click Here To Register...] steht:
Quote:
A buffer object does not have any ownership of the memory it refers to. It is the responsibility of the application to ensure the memory region remains valid until it is no longer required for an I/O operation. When the memory is no longer available, the buffer is said to have been invalidated.
Weiterhin steht [Only registered and activated users can see links. Click Here To Register...]:
Quote:
The buffer is invalidated by any non-const operation called on the given string object.
Das Zerstören deines string-Objektes ist natürlich ebenfalls eine solche Operation. Du nutzt schließlich eine asynchrone Funktion.
11/15/2013 17:59 th0rex#14
Danke dir und euch allen vielmals. Nächstes mal gucke ich in die Dokumentation :D Kann geschlossen werden.